<template><div><p>本文档最新版为 <a href="https://learnku.com/docs/laravel/10.x" target="_blank" rel="noopener noreferrer">10.x</a>，旧版本可能放弃维护，推荐阅读最新版！</p>
<h2 id="queues" tabindex="-1"><a class="header-anchor" href="#queues"><span>Queues</span></a></h2>
<ul>
<li><a href="#introduction">介绍</a>
<ul>
<li><a href="#connections-vs-queues">连接 Vs. 队列</a></li>
<li><a href="#driver-prerequisites">驱动程序说明和先决条件</a></li>
</ul>
</li>
<li><a href="#creating-jobs">创建任务</a>
<ul>
<li><a href="#generating-job-classes">生成任务类</a></li>
<li><a href="#class-structure">任务类结构</a></li>
<li><a href="#unique-jobs">唯一任务</a></li>
<li><a href="#encrypted-jobs">加密任务</a></li>
</ul>
</li>
<li><a href="#job-middleware">任务中间件</a>
<ul>
<li><a href="#rate-limiting">限流</a></li>
<li><a href="#preventing-job-overlaps">防止任务重复执行</a></li>
<li><a href="#throttling-exceptions">异常节流</a></li>
</ul>
</li>
<li><a href="#dispatching-jobs">调度任务</a>
<ul>
<li><a href="#delayed-dispatching">延迟调度</a></li>
<li><a href="#synchronous-dispatching">同步调度</a></li>
<li><a href="#jobs-and-database-transactions">任务 &amp; 数据库事务</a></li>
<li><a href="#job-chaining">任务链</a></li>
<li><a href="#customizing-the-queue-and-connection">自定义队列 &amp; 连接</a></li>
<li><a href="#max-job-attempts-and-timeout">指定最大任务尝试次数 / 超时值</a></li>
<li><a href="#error-handling">错误处理</a></li>
</ul>
</li>
<li><a href="#job-batching">任务批处理</a>
<ul>
<li><a href="#defining-batchable-jobs">定义可批处理任务</a></li>
<li><a href="#dispatching-batches">分派批处理</a></li>
<li><a href="#chains-and-batches">链和批处理</a></li>
<li><a href="#adding-jobs-to-batches">将任务添加到批处理</a></li>
<li><a href="#inspecting-batches">校验批处理</a></li>
<li><a href="#cancelling-batches">取消批处理</a></li>
<li><a href="#batch-failures">批处理失败</a></li>
<li><a href="#pruning-batches">修剪批处理</a></li>
<li><a href="#storing-batches-in-dynamodb">在 DynamoDB 中存储批处理</a></li>
</ul>
</li>
<li><a href="#queueing-closures">队列闭包</a></li>
<li><a href="#running-the-queue-worker">运行队列处理器</a>
<ul>
<li><a href="#the-queue-work-command"><code v-pre>queue:work</code> 命令</a></li>
<li><a href="#queue-priorities">队列优先级</a></li>
<li><a href="#queue-workers-and-deployment">队列处理器 &amp; 部署</a></li>
<li><a href="#job-expirations-and-timeouts">任务过期 &amp; 超时</a></li>
</ul>
</li>
<li><a href="#supervisor-configuration">Supervisor 配置</a></li>
<li><a href="#dealing-with-failed-jobs">处理失败的任务</a>
<ul>
<li><a href="#cleaning-up-after-failed-jobs">任务失败后清理</a></li>
<li><a href="#retrying-failed-jobs">重试失败的任务</a></li>
<li><a href="#ignoring-missing-models">忽略缺失的模型</a></li>
<li><a href="#pruning-failed-jobs">删除失败的任务</a></li>
<li><a href="#storing-failed-jobs-in-dynamodb">在 DynamoDB 中存储失败的任务</a></li>
<li><a href="#disabling-failed-job-storage">禁用失败的任务存储</a></li>
<li><a href="#failed-job-events">失败的任务事件</a></li>
</ul>
</li>
<li><a href="#clearing-jobs-from-queues">从队列中清除任务</a></li>
<li><a href="#monitoring-your-queues">监控队列</a></li>
<li><a href="#testing">测试</a>
<ul>
<li><a href="#faking-a-subset-of-jobs">伪造任务的一个子集</a></li>
<li><a href="#testing-job-chains">测试任务链</a></li>
<li><a href="#testing-job-batches">测试任务批处理</a></li>
<li><a href="#testing-job-queue-interactions">测试任务 / 队列互动</a></li>
</ul>
</li>
<li><a href="#job-events">任务事件</a></li>
</ul>
<h2 id="介绍" tabindex="-1"><a class="header-anchor" href="#介绍"><span>介绍</span></a></h2>
<p>在构建 Web 应用程序时，你可能需要执行一些任务，例如解析和存储上传的 CSV 文件，这些任务在典型的 Web 请求期间需要很长时间才能执行。 值得庆幸的是，Laravel 允许你轻松创建可以在后台处理的队列任务。 通过将时间密集型任务移至队列，你的应用程序可以以极快的速度响应 Web 请求，并为你的客户提供更好的用户体验。</p>
<p>Laravel 队列为各种不同的队列驱动提供统一的队列 API，例如 <a href="https://aws.amazon.com/sqs/" target="_blank" rel="noopener noreferrer">Amazon SQS</a>, <a href="https://redis.io/" target="_blank" rel="noopener noreferrer">Redis</a>，甚至是关系型数据库。</p>
<p>Laravel 队列的配置选项存储在 <code v-pre>config/queue.php</code> 文件中。 在这个文件中，你可以找到框架中包含的每个队列驱动的连接配置，包括数据库， <a href="https://aws.amazon.com/sqs/" target="_blank" rel="noopener noreferrer">Amazon SQS</a>, <a href="https://redis.io/" target="_blank" rel="noopener noreferrer">Redis</a>, 和 <a href="https://beanstalkd.github.io/" target="_blank" rel="noopener noreferrer">Beanstalkd</a> 驱动，以及一个会立即执行任务的同步驱动（用于本地开发）。还包括一个用于丢弃排队任务的 <code v-pre>null</code> 队列驱动。</p>
<blockquote>
<p><strong>注意</strong><br>
Laravel 提供了 Horizon ，适用于 Redis 驱动队列。 Horizon 是一个拥有漂亮仪表盘的配置系统。如需了解更多信息请查看完整的 <a href="https://learnku.com/docs/laravel/11.x/horizonmd" target="_blank" rel="noopener noreferrer">Horizon 文档</a>。</p>
</blockquote>
<h3 id="连接-vs-驱动" tabindex="-1"><a class="header-anchor" href="#连接-vs-驱动"><span>连接 vs 驱动</span></a></h3>
<p>在开始使用 Laravel 队列之前，理解「连接」和「队列」之间的区别非常重要。 在 <code v-pre>config/queue.php</code> 配置文件中，有一个 <code v-pre>connections</code> 连接选项。 此选项定义连接某个驱动（如 Amazon SQS、Beanstalk 或 Redis）。然而，任何给定的队列连接都可能有多个「队列」，这些「队列」可能被认为是不同的堆栈或成堆的排队任务。</p>
<p>请注意， <code v-pre>queue</code> 配置文件中的每个连接配置示例都包含一个 <code v-pre>queue</code> 属性。这是将任务发送到给定连接时将被分配到的默认队列。换句话说，如果你没有显式地定义任务应该被发送到哪个队列，那么该任务将被放置在连接配置的 <code v-pre>queue</code> 属性中定义的队列上：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>ProcessPodcast</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 这个任务将被推送到默认队列...</span></span>
<span class="line"><span class="token class-name static-context">ProcessPodcast</span><span class="token operator">::</span><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 这个任务将被推送到「emails」队列...</span></span>
<span class="line"><span class="token class-name static-context">ProcessPodcast</span><span class="token operator">::</span><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onQueue</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'emails'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>有些应用程序可能不需要将任务推到多个队列中，而是倾向于使用一个简单的队列。然而，如果希望对任务的处理方式进行优先级排序或分段时，将任务推送到多个队列就显得特别有用，因为 Laravel 队列工作程序允许你指定哪些队列应该按优先级处理。例如，如果你将任务推送到一个 <code v-pre>high</code> 队列，你可能会运行一个赋予它们更高处理优先级的 worker：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:work <span class="token parameter variable">--queue</span><span class="token operator">=</span>high,default</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="驱动程序说明和先决条件" tabindex="-1"><a class="header-anchor" href="#驱动程序说明和先决条件"><span>驱动程序说明和先决条件</span></a></h3>
<h4 id="数据库" tabindex="-1"><a class="header-anchor" href="#数据库"><span>数据库</span></a></h4>
<p>要使用 <code v-pre>database</code> 队列驱动，你需要一个数据库表来保存任务。通常，这包含在 Laravel 默认的 <code v-pre>0001_01_01_000002_create_jobs_table.php</code> <a href="https://learnku.com/docs/laravel/11.x/migrationsmd" target="_blank" rel="noopener noreferrer">数据库迁移</a> 中； 然而，如果你的应用程序不包含此迁移，可以使用 <code v-pre>make:queue-table</code> Artisan 命令创建它：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan make:queue-table</span>
<span class="line"></span>
<span class="line">php artisan migrate</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="redis" tabindex="-1"><a class="header-anchor" href="#redis"><span>Redis</span></a></h4>
<p>要使用 <code v-pre>redis</code> 队列驱动程序，需要在 <code v-pre>config/database.php</code> 配置文件中配置一个 redis 数据库连接。</p>
<blockquote>
<p>注意<br>
<code v-pre>serializer</code> 和 <code v-pre>compression</code> 选项不被 <code v-pre>redis</code> 队列驱动支持。</p>
</blockquote>
<p><strong>Redis 集群</strong></p>
<p>如果你的 Redis 队列当中使用了 Redis 集群，那么你的队列名称就必须包含一个 <a href="https://redis.io/docs/reference/cluster-spec/#hash-tags" target="_blank" rel="noopener noreferrer">key hash tag</a>。这是为了确保一个给定队列的所有 Redis 键都被放在同一个哈希槽中：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token string single-quoted-string">'redis'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'driver'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'redis'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'connection'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'REDIS_QUEUE_CONNECTION'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'queue'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'REDIS_QUEUE'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'{default}'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'retry_after'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'REDIS_QUEUE_RETRY_AFTER'</span><span class="token punctuation">,</span> <span class="token number">90</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'block_for'</span> <span class="token operator">=></span> <span class="token constant">null</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'after_commit'</span> <span class="token operator">=></span> <span class="token constant boolean">false</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><strong>阻塞</strong></p>
<p>在使用 Redis 队列时，您可以使用 <code v-pre>block_for</code> 配置选项来指定在遍历 worker 循环和重新轮询 Redis 数据库之前，驱动程序需要等待多长时间才能使任务变得可用。</p>
<p>根据你的队列负载调整此值要比连续轮询 Redis 数据库中的新任务更加有效。例如，你可以将值设置为 <code v-pre>5</code> 以指示驱动程序在等待任务变得可用时应该阻塞 5 秒：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token string single-quoted-string">'redis'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'driver'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'redis'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'connection'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'REDIS_QUEUE_CONNECTION'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'queue'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'REDIS_QUEUE'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'default'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'retry_after'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'REDIS_QUEUE_RETRY_AFTER'</span><span class="token punctuation">,</span> <span class="token number">90</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'block_for'</span> <span class="token operator">=></span> <span class="token number">5</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'after_commit'</span> <span class="token operator">=></span> <span class="token constant boolean">false</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>注意</strong><br>
将 <code v-pre>block_for</code> 设置成 <code v-pre>0</code> 将导致队列任务一直阻塞，直到某一个任务变得可用。这也将防止在下一个任务被处理之前处理诸如 SIGTERM 之类的信号。</p>
</blockquote>
<h4 id="其他驱动所需的先决条件" tabindex="-1"><a class="header-anchor" href="#其他驱动所需的先决条件"><span>其他驱动所需的先决条件</span></a></h4>
<p>列出的队列驱动需要如下的依赖，这些依赖可通过 Composer 包管理器进行安装：</p>
<ul>
<li>Amazon SQS: <code v-pre>aws/aws-sdk-php ~3.0</code></li>
<li>Beanstalkd: <code v-pre>pda/pheanstalk ~5.0</code></li>
<li>Redis: <code v-pre>predis/predis ~2.0</code> 或 phpredis PHP 扩展</li>
</ul>
<h2 id="创建任务" tabindex="-1"><a class="header-anchor" href="#创建任务"><span>创建任务</span></a></h2>
<h3 id="生成任务类" tabindex="-1"><a class="header-anchor" href="#生成任务类"><span>生成任务类</span></a></h3>
<p>默认情况下，应用程序的所有的可排队任务都被存储在了<code v-pre>app/Jobs</code> 目录中。如果 <code v-pre>app/Jobs</code> 目录不存在，当你运行 <code v-pre>make:job</code> Artisan 命令时，将会自动创建该目录：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan make:job ProcessPodcast</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>生成的类将会实现 <code v-pre>Illuminate\Contracts\Queue\ShouldQueue</code> 接口， 告诉 Laravel ，该任务应该推入队列以异步的方式运行。</p>
<blockquote>
<p>技巧<br>
任务模板可以使用 <a href="https://learnku.com/docs/laravel/11.x/artisanmd/" target="_blank" rel="noopener noreferrer">模板发布</a> 来自定义任务 stub 。</p>
</blockquote>
<h3 id="任务类结构" tabindex="-1"><a class="header-anchor" href="#任务类结构"><span>任务类结构</span></a></h3>
<p>任务类非常简单，通常只包含一个 <code v-pre>handle</code> 方法，在队列处理任务时将会调用它。让我们看一个任务类的示例。在这个例子中，我们假设我们管理一个 podcast 服务，并且需要在上传的 podcast 文件发布之前对其进行处理：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Jobs</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Podcast</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Services<span class="token punctuation">\</span>AudioProcessor</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Bus<span class="token punctuation">\</span>Queueable</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>ShouldQueue</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Foundation<span class="token punctuation">\</span>Bus<span class="token punctuation">\</span>Dispatchable</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>InteractsWithQueue</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>SerializesModels</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">ProcessPodcast</span> <span class="token keyword">implements</span> <span class="token class-name">ShouldQueue</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">use</span> <span class="token package">Dispatchable</span><span class="token punctuation">,</span> InteractsWithQueue<span class="token punctuation">,</span> Queueable<span class="token punctuation">,</span> SerializesModels<span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 创建一个新的任务实例.</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">__construct</span><span class="token punctuation">(</span></span>
<span class="line">        <span class="token keyword">public</span> <span class="token class-name type-declaration">Podcast</span> <span class="token variable">$podcast</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 运行任务.</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">handle</span><span class="token punctuation">(</span><span class="token class-name type-declaration">AudioProcessor</span> <span class="token variable">$processor</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token comment">// 处理上传的 podcast...</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在此示例中，请注意我们能够直接将 <a href="https://learnku.com/docs/laravel/11.x/eloquentmd/16702" target="_blank" rel="noopener noreferrer">Eloquent模型</a> 传递给队列任务的构造函数。由于任务使用了<code v-pre>SerializesModels</code>特性，Eloquent模型及其加载的关系将会在任务处理时优雅地进行序列化和反序列化。</p>
<p>如果您的队列任务在其构造函数中接受了一个Eloquent模型，只有模型的标识符会被序列化到队列中。当任务实际被处理时，队列系统会自动从数据库中重新获取完整的模型实例及其加载的关系。这种模型序列化的方法使得发送到队列驱动程序的任务负载要小得多。</p>
<h4 id="handle-方法依赖注入" tabindex="-1"><a class="header-anchor" href="#handle-方法依赖注入"><span><code v-pre>handle</code> 方法依赖注入</span></a></h4>
<p>当任务由队列处理时，会调用 <code v-pre>handle</code> 方法。请注意，我们能够在任务的 <code v-pre>handle</code> 方法上类型提示依赖项。Laravel的 <a href="https://learnku.com/docs/laravel/11.x/containermd/16654" target="_blank" rel="noopener noreferrer">服务容器</a> 会自动注入这些依赖。</p>
<p>如果您希望完全控制服务容器如何将依赖项注入到 <code v-pre>handle</code> 方法中，可以使用容器的 <code v-pre>bindMethod</code> 方法。<code v-pre>bindMethod</code> 方法接受一个回调，该回调接收任务实例和容器本身。在回调内，您可以自由地以任何方式调用 <code v-pre>handle</code> 方法。通常，您应该在 <code v-pre>App\Providers\AppServiceProvider</code> <a href="https://learnku.com/docs/laravel/11.x/providersmd/16655" target="_blank" rel="noopener noreferrer">服务提供者</a> 的 <code v-pre>boot</code> 方法中调用此方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>ProcessPodcast</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Services<span class="token punctuation">\</span>AudioProcessor</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Foundation<span class="token punctuation">\</span>Application</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$this</span><span class="token operator">-></span><span class="token property">app</span><span class="token operator">-></span><span class="token function">bindMethod</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token class-name static-context">ProcessPodcast</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'handle'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">ProcessPodcast</span> <span class="token variable">$job</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Application</span> <span class="token variable">$app</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$job</span><span class="token operator">-></span><span class="token function">handle</span><span class="token punctuation">(</span><span class="token variable">$app</span><span class="token operator">-></span><span class="token function">make</span><span class="token punctuation">(</span><span class="token class-name static-context">AudioProcessor</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>警告</strong><br>
二进制数据，如原始图像内容，在传递给队列任务之前应通过 <code v-pre>base64_encode</code> 函数进行编码。否则，任务在放入队列时可能无法正确地序列化为JSON。</p>
</blockquote>
<h4 id="队列关系" tabindex="-1"><a class="header-anchor" href="#队列关系"><span>队列关系</span></a></h4>
<p>因为加载的关系也会被序列化，所以处理序列化任务的字符串有时会变得相当大。此外，当任务反序列化并且从数据库重新检索模型关系时，它们将被完整检索。在任务队列过程中模型被序列化之前应用的任何关系关联，在作业反序列化时不会应用。因此，如果你希望在队列任务中处理给定关系的一个子集，你应该在队列作业中重新限定该关系。</p>
<p>或者为了防止该关系被序列化，可以在设置属性值时对模型调用 <code v-pre>withoutRelations</code> 方法。此方法将返回没有加载关系的模型实例：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 创建一个新的任务实例.</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">__construct</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Podcast</span> <span class="token variable">$podcast</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">podcast</span> <span class="token operator">=</span> <span class="token variable">$podcast</span><span class="token operator">-></span><span class="token function">withoutRelations</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果使用 PHP 构造函数，并希望指定一个 Eloquent 模型不应该序列化它的关系，你可以使用 <code v-pre>WithoutRelations</code> 属性 :</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>Attributes<span class="token punctuation">\</span>WithoutRelations</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 创建一个新的任务实例.</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">__construct</span><span class="token punctuation">(</span></span>
<span class="line">    <span class="token attribute"><span class="token delimiter punctuation">#[</span><span class="token attribute-content"><span class="token attribute-class-name class-name">WithoutRelations</span></span><span class="token delimiter punctuation">]</span></span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token class-name type-declaration">Podcast</span> <span class="token variable">$podcast</span></span>
<span class="line"><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果任务接收到的是 Eloquent 模型的集合或数组而不是单个模型，则集合内的模型在作业反序列化和执行时不会恢复它们的关系。这样做是为了防止处理大量模型的作业产生过多的资源使用。</p>
<h3 id="唯一任务" tabindex="-1"><a class="header-anchor" href="#唯一任务"><span>唯一任务</span></a></h3>
<blockquote>
<p><strong>注意</strong><br>
唯一任务需要支持 <a href="https://learnku.com/docs/laravel/11.x/cachemd/16673" target="_blank" rel="noopener noreferrer">locks</a> 的缓存驱动程序。 目前， <code v-pre>memcached</code>, <code v-pre>redis</code>, <code v-pre>dynamodb</code>, <code v-pre>database</code>, <code v-pre>file</code>, 和 <code v-pre>array</code> 缓存驱动支持原子锁。 此外，独特的任务约束不适用于批次内的任务。</p>
</blockquote>
<p>有时，你可能希望确保在任何时间点队列中只有一个特定任务的实例。你可以通过在你的工作类上实现 <code v-pre>ShouldBeUnique</code> 接口来做到这一点。这个接口不需要你在你的类上定义任何额外的方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>ShouldQueue</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>ShouldBeUnique</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">UpdateSearchIndex</span> <span class="token keyword">implements</span> <span class="token class-name">ShouldQueue</span><span class="token punctuation">,</span> ShouldBeUnique</span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token operator">...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>以上示例中， <code v-pre>UpdateSearchIndex</code> 任务是唯一的。因此，如果任务的另一个实例已经在队列中并且尚未完成处理，则不会分派该任务。</p>
<p>在某些情况下，你可能想要定义一个使任务唯一的特定「键」，或者你可能想要指定一个超时时间，超过该时间任务不再保持唯一。为此，你可以在任务类上定义 <code v-pre>uniqueId</code> 和 <code v-pre>uniqueFor</code> 属性或方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Product</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>ShouldQueue</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>ShouldBeUnique</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">UpdateSearchIndex</span> <span class="token keyword">implements</span> <span class="token class-name">ShouldQueue</span><span class="token punctuation">,</span> ShouldBeUnique</span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 产品实例.</span>
<span class="line">     *</span>
<span class="line">     * <span class="token keyword">@var</span> <span class="token class-name"><span class="token punctuation">\</span>App<span class="token punctuation">\</span>Product</span></span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token variable">$product</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 任务的唯一锁将在多少秒后被释放。</span>
<span class="line">     *</span>
<span class="line">     * <span class="token keyword">@var</span> <span class="token class-name"><span class="token keyword">int</span></span></span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token variable">$uniqueFor</span> <span class="token operator">=</span> <span class="token number">3600</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 任务的唯一锁将被释放的秒数。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">uniqueId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">string</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">product</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>以上示例中， <code v-pre>UpdateSearchIndex</code> 任务中的 product ID 是唯一的。因此，在现有任务完成处理之前，任何具有相同 product ID 的任务都将被忽略。此外，如果现有任务在一小时内没有得到处理，则释放唯一锁，并将具有相同唯一键的另一个任务分派到该队列。</p>
<blockquote>
<p><strong>注意</strong><br>
如果你的应用程序从多个 web 服务器或容器分派任务，你应该确保你的所有服务器都与同一个中央缓存服务器通信，以便 Laravel 能够准确确定任务是否唯一。</p>
</blockquote>
<h4 id="在任务处理开始前保证唯一" tabindex="-1"><a class="header-anchor" href="#在任务处理开始前保证唯一"><span>在任务处理开始前保证唯一</span></a></h4>
<p>默认情况下，一个唯一的任务在处理完成后或者在所有重试尝试失败后会「解锁」。然而，在某些情况下，你可能希望你的任务在处理之前立即解锁。要做到这一点，你的任务应该实现 <code v-pre>ShouldBeUniqueUntilProcessing</code> 契约而不是 <code v-pre>ShouldBeUnique</code> 契约：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Product</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>ShouldQueue</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>ShouldBeUniqueUntilProcessing</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">UpdateSearchIndex</span> <span class="token keyword">implements</span> <span class="token class-name">ShouldQueue</span><span class="token punctuation">,</span> ShouldBeUniqueUntilProcessing</span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="唯一任务锁" tabindex="-1"><a class="header-anchor" href="#唯一任务锁"><span>唯一任务锁</span></a></h4>
<p>在底层实现中，当一个 <code v-pre>ShouldBeUnique</code> 任务被派发时，Laravel 会尝试使用 <code v-pre>uniqueId</code> 键获得一个 <a href="https://learnku.com/docs/laravel/11.x/cachemd#atomic-locks" target="_blank" rel="noopener noreferrer">锁</a>。如果没有获得锁，任务就不会被派发。这个锁在任务处理完成或所有重试尝试失败后会被释放。默认情况下，Laravel 将使用默认缓存驱动来获取这个锁。然而，如果你希望使用另一个驱动来获取锁，你可以定义一个 <code v-pre>uniqueVia</code> 方法，该方法返回应该使用的缓存驱动：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Cache<span class="token punctuation">\</span>Repository</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Cache</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">UpdateSearchIndex</span> <span class="token keyword">implements</span> <span class="token class-name">ShouldQueue</span><span class="token punctuation">,</span> ShouldBeUnique</span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token operator">...</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 获取唯一任务锁的缓存驱动。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">uniqueVia</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">Repository</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token class-name static-context">Cache</span><span class="token operator">::</span><span class="token function">driver</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'redis'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>技巧</strong><br>
如果只需要限制任务的并发处理，请改用 <a href="https://learnku.com/docs/laravel/11.x/queuesmd#preventing-job-overlaps" target="_blank" rel="noopener noreferrer"><code v-pre>WithoutOverlapping</code></a> 任务中间件。</p>
</blockquote>
<h3 id="加密任务" tabindex="-1"><a class="header-anchor" href="#加密任务"><span>加密任务</span></a></h3>
<p>Laravel 允许你通过<a href="https://learnku.com/docs/laravel/11.x/encryptionmd" target="_blank" rel="noopener noreferrer">加密</a>来确保任务数据的隐私和完整性。要开始使用，只需向作业类添加 <code v-pre>ShouldBeEncrypted</code> 接口。一旦在类上添加了这个接口，Laravel 将自动加密你的任务后再推送到队列：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>ShouldBeEncrypted</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>ShouldQueue</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">UpdateSearchIndex</span> <span class="token keyword">implements</span> <span class="token class-name">ShouldQueue</span><span class="token punctuation">,</span> ShouldBeEncrypted</span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="任务中间件" tabindex="-1"><a class="header-anchor" href="#任务中间件"><span>任务中间件</span></a></h2>
<p>任务中间件允许你围绕排队任务的执行封装自定义逻辑，从而减少了任务本身的样板代码。例如，看下面的 <code v-pre>handle</code> 方法，它利用了 Laravel 的 Redis 速率限制特性，允许每 5 秒只处理一个任务：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Redis</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * Execute the job.</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">handle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Redis</span><span class="token operator">::</span><span class="token function">throttle</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'key'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">block</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">allow</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">every</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token function">info</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'取得了锁...'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 处理任务...</span></span>
<span class="line">    <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token comment">// 无法获取锁...</span></span>
<span class="line"></span>
<span class="line">        <span class="token keyword">return</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">release</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>虽然这段代码是有效的， 但是 <code v-pre>handle</code> 方法的结构却变得杂乱，因为它掺杂了 Redis 速率限制逻辑。此外，其他任务需要使用速率限制的时候，只能将限制逻辑复制一次。</p>
<p>我们可以定义一个处理速率限制的任务中间件，而不是在 handle 方法中定义速率限制。Laravel 没有任务中间件的默认位置，所以你可以将任务中间件放置在你喜欢的任何位置。在本例中，我们将把中间件放在 <code v-pre>app/Jobs/Middleware</code> 目录：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>Middleware</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Closure</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Redis</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">RateLimited</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 处理队列任务</span>
<span class="line">     *</span>
<span class="line">     * <span class="token keyword">@param</span>  <span class="token class-name"><span class="token punctuation">\</span>Closure</span>(object): void  $next</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">handle</span><span class="token punctuation">(</span><span class="token keyword type-hint">object</span> <span class="token variable">$job</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Closure</span> <span class="token variable">$next</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token class-name static-context">Redis</span><span class="token operator">::</span><span class="token function">throttle</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'key'</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token operator">-></span><span class="token function">block</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">allow</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">every</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token operator">-></span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">use</span> <span class="token punctuation">(</span><span class="token variable">$job</span><span class="token punctuation">,</span> <span class="token variable">$next</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">                    <span class="token comment">// 已获得锁...</span></span>
<span class="line"></span>
<span class="line">                    <span class="token variable">$next</span><span class="token punctuation">(</span><span class="token variable">$job</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">                <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">use</span> <span class="token punctuation">(</span><span class="token variable">$job</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">                    <span class="token comment">// 没有获取到锁...</span></span>
<span class="line"></span>
<span class="line">                    <span class="token variable">$job</span><span class="token operator">-></span><span class="token function">release</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">                <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>正如你看到的，类似于 <a href="https://learnku.com/docs/laravel/11.x/middleware" target="_blank" rel="noopener noreferrer">路由中间件</a>，任务中间件接收正在处理队列任务以及一个回调来继续处理队列任务。</p>
<p>在任务中间件被创建以后，他们可能被关联到通过从任务的 <code v-pre>middleware</code>方法返回的任务。这个方法并不存在于 <code v-pre>make:job</code> Artisan 命令搭建的任务中，所以你需要将它添加到你自己的任务类的定义中：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>RateLimited</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 获取一个可以被传递通过的中间件任务</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">array</span></span>&lt;int, object></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">array</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token keyword">new</span> <span class="token class-name">RateLimited</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>技巧</strong><br>
任务中间件也可以分配其他可队列处理的监听事件当中，比如邮件，通知等。</p>
</blockquote>
<h3 id="访问限制" tabindex="-1"><a class="header-anchor" href="#访问限制"><span>访问限制</span></a></h3>
<p>尽管我们刚刚演示了如何编写自己的访问限制的任务中间件，但 Laravel 实际上内置了一个访问限制中间件，你可以利用它来限制任务。与 <a href="https://learnku.com/docs/laravel/11.x/routingmd/16657#789d24%23defining-rate-limiters" target="_blank" rel="noopener noreferrer">路由限流器</a> 一样，任务访问限制器是使用 <code v-pre>RateLimiter</code> facade 的 <code v-pre>for</code> 方法定义的。</p>
<p>例如，你可能希望允许用户每小时备份一次数据，但不对高级客户施加此类限制。为此，可以在 <code v-pre>AppServiceProvider</code> 的 <code v-pre>boot</code> 方法中定义 <code v-pre>RateLimiter</code>：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Cache<span class="token punctuation">\</span>RateLimiting<span class="token punctuation">\</span>Limit</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>RateLimiter</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 注册应用程序服务</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">RateLimiter</span><span class="token operator">::</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'backups'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token keyword type-hint">object</span> <span class="token variable">$job</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token variable">$job</span><span class="token operator">-></span><span class="token property">user</span><span class="token operator">-></span><span class="token function">vipCustomer</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">                    <span class="token operator">?</span> <span class="token class-name static-context">Limit</span><span class="token operator">::</span><span class="token function">none</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">                    <span class="token punctuation">:</span> <span class="token class-name static-context">Limit</span><span class="token operator">::</span><span class="token function">perHour</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">by</span><span class="token punctuation">(</span><span class="token variable">$job</span><span class="token operator">-></span><span class="token property">user</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在上面的例子中，我们定义了一个小时访问限制；但是，你可以使用 <code v-pre>perMinute</code> 方法轻松定义基于分钟的访问限制。此外，你可以将任何值传递给访问限制的 <code v-pre>by</code> 方法，但是，这个值通常用于按客户来区分不同的访问限制：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">return</span> <span class="token class-name static-context">Limit</span><span class="token operator">::</span><span class="token function">perMinute</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">by</span><span class="token punctuation">(</span><span class="token variable">$job</span><span class="token operator">-></span><span class="token property">user</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>定义速率限制后，你可以使用 <code v-pre>Illuminate\Queue\Middleware\RateLimited</code> 中间件将速率限制器附加到备份任务。 每次任务超过速率限制时，此中间件都会根据速率限制持续时间以适当的延迟将任务释放回队列。</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>RateLimited</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 获取任务时，应该通过的中间件</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">array</span></span>&lt;int, object></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">array</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token keyword">new</span> <span class="token class-name">RateLimited</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'backups'</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>将速率受限的任务释放回队列仍然会增加任务的 「尝试」总数。你可能希望相应地调整你的任务类上的 <code v-pre>tries</code> 和 <code v-pre>maxExceptions</code> 属性。或者，你可能希望使用 <code v-pre>retryUntil</code> <a href="#time-based-attempts">方法</a> 来定义不再尝试任务之前的时间量。</p>
<p>如果你不想在速率限制时重试任务，你可以使用 <code v-pre>dontRelease</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 获取任务时，应该通过的中间件</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">array</span></span>&lt;int, object></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">array</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">RateLimited</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'backups'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">dontRelease</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>技巧</strong><br>
如果你使用 Redis，你可以使用 Illuminate\Queue\Middleware\RateLimitedWithRedis 中间件，它针对 Redis 进行了微调，比基本的限速中间件更高效。</p>
</blockquote>
<h3 id="防止任务重叠" tabindex="-1"><a class="header-anchor" href="#防止任务重叠"><span>防止任务重叠</span></a></h3>
<p>Laravel 包含一个 <code v-pre>Illuminate\Queue\Middleware\WithoutOverlapping</code> 中间件，允许你根据任意键防止任务重叠。当排队的任务正在修改一次只能由一个任务修改的资源时，这会很有帮助。</p>
<p>例如，假设你有一个更新用户信用评分的排队任务，并且你希望防止同一用户 ID 的信用评分更新任务重叠。为此，你可以从任务的 <code v-pre>middleware</code> 方法返回 <code v-pre>WithoutOverlapping</code> 中间件：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>WithoutOverlapping</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 获取任务时，应该通过的中间件。</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">array</span></span>&lt;int, object></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">array</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token keyword">new</span> <span class="token class-name">WithoutOverlapping</span><span class="token punctuation">(</span><span class="token variable">$this</span><span class="token operator">-></span><span class="token property">user</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>任何重叠的任务都将被释放回队列。你还可以指定再次尝试释放的任务之前必须经过的秒数：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 获取任务时，应该通过的中间件。</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">array</span></span>&lt;int, object></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">array</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">WithoutOverlapping</span><span class="token punctuation">(</span><span class="token variable">$this</span><span class="token operator">-></span><span class="token property">order</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">releaseAfter</span><span class="token punctuation">(</span><span class="token number">60</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你想立即删除任何重叠的任务，你可以使用 <code v-pre>dontRelease</code> 方法，这样它们就不会被重试：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 获取任务时，应该通过的中间件。</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">array</span></span>&lt;int, object></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">array</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">WithoutOverlapping</span><span class="token punctuation">(</span><span class="token variable">$this</span><span class="token operator">-></span><span class="token property">order</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">dontRelease</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><code v-pre>WithoutOverlapping</code> 中间件由 Laravel 的原子锁特性提供支持。有时，你的任务可能会以未释放锁的方式意外失败或超时。因此，你可以使用 <code v-pre>expireAfter</code> 方法显式定义锁定过期时间。例如，下面的示例将指示 Laravel 在任务开始处理三分钟后释放 <code v-pre>WithoutOverlapping</code> 锁：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 获取任务时，应该通过的中间件。</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">array</span></span>&lt;int, object></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">array</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">WithoutOverlapping</span><span class="token punctuation">(</span><span class="token variable">$this</span><span class="token operator">-></span><span class="token property">order</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">expireAfter</span><span class="token punctuation">(</span><span class="token number">180</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>注意</strong><br>
<code v-pre>WithoutOverlapping</code> 中间件需要支持 <a href="https://learnku.com/docs/laravel/11.x/cache#atomic-locks" target="_blank" rel="noopener noreferrer">locks</a> 的缓存驱动程序。目前，<code v-pre>memcached</code>、<code v-pre>redis</code>、<code v-pre>dynamodb</code>、<code v-pre>database</code>、<code v-pre>file</code> 和 <code v-pre>array</code> 缓存驱动支持原子锁。</p>
</blockquote>
<h4 id="跨任务类别共享锁" tabindex="-1"><a class="header-anchor" href="#跨任务类别共享锁"><span>跨任务类别共享锁</span></a></h4>
<p>默认情况下，<code v-pre>WithoutOverlapping</code> 中间件只会阻止同一类的重叠任务。 因此，尽管两个不同的任务类可能使用相同的锁，但不会阻止它们重叠。 但是，你可以使用 <code v-pre>shared</code> 方法指示 Laravel 跨任务类应用锁：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>WithoutOverlapping</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">ProviderIsDown</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">array</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">WithoutOverlapping</span><span class="token punctuation">(</span><span class="token string double-quoted-string">"status:<span class="token interpolation"><span class="token punctuation">{</span><span class="token variable">$this</span><span class="token operator">-></span><span class="token property">provider</span><span class="token punctuation">}</span></span>"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">shared</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">ProviderIsUp</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">array</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">WithoutOverlapping</span><span class="token punctuation">(</span><span class="token string double-quoted-string">"status:<span class="token interpolation"><span class="token punctuation">{</span><span class="token variable">$this</span><span class="token operator">-></span><span class="token property">provider</span><span class="token punctuation">}</span></span>"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">shared</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="节流限制异常" tabindex="-1"><a class="header-anchor" href="#节流限制异常"><span>节流限制异常</span></a></h3>
<p>Laravel 包含一个 <code v-pre>Illuminate\Queue\Middleware\ThrottlesExceptions</code> 中间件，允许你限制异常。一旦任务抛出给定数量的异常，所有进一步执行该任务的尝试都会延迟，直到经过指定的时间间隔。该中间件对于与不稳定的第三方服务交互的任务特别有用。</p>
<p>例如，让我们想象一个队列任务与开始抛出异常的第三方 API 交互。要限制异常，你可以从任务的 <code v-pre>middleware</code> 方法返回 <code v-pre>ThrottlesExceptions</code> 中间件。通常，此中间件应与实现 <a href="#time-based-attempts">基于时间的尝试</a>的任务配对：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">DateTime</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>ThrottlesExceptions</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 获取任务时，应该通过的中间件。</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">array</span></span>&lt;int, object></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">array</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token keyword">new</span> <span class="token class-name">ThrottlesExceptions</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 确定任务应该超时的时间。</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">retryUntil</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">DateTime</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">addMinutes</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>中间件接受的第一个构造函数参数是任务在被限制之前可以抛出的异常数，而第二个构造函数参数是在任务被限制后再次尝试之前应该经过的分钟数。在上面的代码示例中，如果任务在 5 分钟内抛出 10 个异常，我们将等待 5 分钟，然后再次尝试该任务。</p>
<p>当任务抛出异常但尚未达到异常阈值时，通常会立即重试该任务。但是，你可以通过在将中间件附加到任务时调用 <code v-pre>backoff</code> 方法来指定此类任务应延迟的分钟数：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>ThrottlesExceptions</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 获取任务时，应该通过的中间件</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">array</span></span>&lt;int, object></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">array</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">ThrottlesExceptions</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">backoff</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在内部，这个中间件使用 Laravel 的缓存系统来实现速率限制，并利用任务的类名作为缓存 「键」。 在将中间件附加到任务时，你可以通过调用 <code v-pre>by</code> 法来覆盖此键。 如果你有多个任务与同一个第三方服务交互并且你希望它们共享一个共同的节流 「桶」，这可能会很有用：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>ThrottlesExceptions</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 获取任务时，应该通过的中间件</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">array</span></span>&lt;int, object></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">array</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">ThrottlesExceptions</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">by</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'key'</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>默认情况下，这个中间件将限制每个异常。你可以通过在附加中间件到任务时调用 <code v-pre>when</code> 方法来修改这种行为。只有当提供给 <code v-pre>when</code> 方法的闭包返回 <code v-pre>true</code> 时，异常才会被节流：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Client<span class="token punctuation">\</span>HttpClientException</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>ThrottlesExceptions</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 获取任务时，应该通过的中间件</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">array</span></span>&lt;int, object></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">array</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">ThrottlesExceptions</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">when</span><span class="token punctuation">(</span></span>
<span class="line">        <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Throwable</span> <span class="token variable">$throwable</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token variable">$throwable</span> <span class="token keyword">instanceof</span> <span class="token class-name">HttpClientException</span></span>
<span class="line">    <span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你希望将被节流的异常报告给你的应用程序的异常处理程序，你可以在附加中间件到任务时调用 <code v-pre>report</code> 方法来做到这一点。你也可以提供一个闭包给 <code v-pre>report</code> 方法，并且如果给定闭包返回 <code v-pre>true</code>，异常才会被报告：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Client<span class="token punctuation">\</span>HttpClientException</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>ThrottlesExceptions</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 获取任务时，应该通过的中间件</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">array</span></span>&lt;int, object></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">array</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">ThrottlesExceptions</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">report</span><span class="token punctuation">(</span></span>
<span class="line">        <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Throwable</span> <span class="token variable">$throwable</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token variable">$throwable</span> <span class="token keyword">instanceof</span> <span class="token class-name">HttpClientException</span></span>
<span class="line">    <span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>技巧</strong><br>
如果你使用的是 Redis，你可以使用 <code v-pre>Illuminate\Queue\Middleware\ThrottlesExceptionsWithRedis</code> 中间件，它为 Redis 进行了优化，比基本的异常节流中间件更高效。</p>
</blockquote>
<h2 id="调度任务" tabindex="-1"><a class="header-anchor" href="#调度任务"><span>调度任务</span></a></h2>
<p>一旦你写好了你的任务类，你可以使用任务本身的 <code v-pre>dispatch</code> 方法来调度它。传递给 <code v-pre>dispatch</code> 方法的参数将被提供给任务的构造函数：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>ProcessPodcast</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Podcast</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>RedirectResponse</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PodcastController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 存储一个新的播客。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">store</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">RedirectResponse</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$podcast</span> <span class="token operator">=</span> <span class="token class-name static-context">Podcast</span><span class="token operator">::</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token comment">/* ... */</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// ...</span></span>
<span class="line"></span>
<span class="line">        <span class="token class-name static-context">ProcessPodcast</span><span class="token operator">::</span><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token variable">$podcast</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/podcasts'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你想有条件地分派任务，你可以使用 <code v-pre>dispatchIf</code> 和 <code v-pre>dispatchUnless</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">ProcessPodcast</span><span class="token operator">::</span><span class="token function">dispatchIf</span><span class="token punctuation">(</span><span class="token variable">$accountActive</span><span class="token punctuation">,</span> <span class="token variable">$podcast</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">ProcessPodcast</span><span class="token operator">::</span><span class="token function">dispatchUnless</span><span class="token punctuation">(</span><span class="token variable">$accountSuspended</span><span class="token punctuation">,</span> <span class="token variable">$podcast</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在新的 Laravel 应用程序中，默认的队列驱动是 <code v-pre>sync</code> 驱动。这个驱动在当前请求的前台同步执行任务，通常在本地开发中很方便。如果你想在后台处理队列任务，你可以在应用程序的 <code v-pre>config/queue.php</code> 配置文件中指定不同的队列驱动。</p>
<h3 id="延迟调度" tabindex="-1"><a class="header-anchor" href="#延迟调度"><span>延迟调度</span></a></h3>
<p>如果你想指定一个任务不应该立即可供队列工作器处理，当调度任务时，你可以使用 <code v-pre>delay</code> 方法。例如，让我们指定一个任务应该在调度后 10 分钟才能被处理：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>ProcessPodcast</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Podcast</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>RedirectResponse</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PodcastController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 储存一个新的播客</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">store</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">RedirectResponse</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$podcast</span> <span class="token operator">=</span> <span class="token class-name static-context">Podcast</span><span class="token operator">::</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token comment">/* ... */</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// ...</span></span>
<span class="line"></span>
<span class="line">        <span class="token class-name static-context">ProcessPodcast</span><span class="token operator">::</span><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token variable">$podcast</span><span class="token punctuation">)</span></span>
<span class="line">                    <span class="token operator">-></span><span class="token function">delay</span><span class="token punctuation">(</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">addMinutes</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/podcasts'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>注意</strong><br>
Amazon SQS 队列服务的最大延迟时间为 15 分钟。</p>
</blockquote>
<h4 id="响应发送到浏览器后调度" tabindex="-1"><a class="header-anchor" href="#响应发送到浏览器后调度"><span>响应发送到浏览器后调度</span></a></h4>
<p>另外，如果你的 web 服务器使用 FastCGI，<code v-pre>dispatchAfterResponse</code> 方法延迟调度作业，直到 HTTP 响应发送到用户浏览器之后。这将仍然允许用户开始使用应用程序，即使一个排队的任务仍然在执行。这通常只应该用于执行时间大约一秒钟的任务，例如发送电子邮件。由于它们是在当前 HTTP 请求中处理的，以这种方式调度的任务不需要运行队列工作器就能被处理：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>SendNotification</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">SendNotification</span><span class="token operator">::</span><span class="token function">dispatchAfterResponse</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你也可以 <code v-pre>dispatch</code> 一个闭包并将 <code v-pre>afterResponse</code> 方法链式调用到 <code v-pre>dispatch</code> 帮助器上，以在发送 HTTP 响应后执行闭包：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Mail<span class="token punctuation">\</span>WelcomeMessage</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Mail</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Mail</span><span class="token operator">::</span><span class="token function">to</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'taylor@example.com'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">send</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">WelcomeMessage</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">afterResponse</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="同步调度" tabindex="-1"><a class="header-anchor" href="#同步调度"><span>同步调度</span></a></h3>
<p>如果你想立即（同步）调度任务，你可以使用 <code v-pre>dispatchSync</code> 方法。使用此方法时，任务不会排队，会在当前进程内立即执行：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>ProcessPodcast</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Podcast</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>RedirectResponse</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PodcastController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 存储一个新的播客</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">store</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">RedirectResponse</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$podcast</span> <span class="token operator">=</span> <span class="token class-name static-context">Podcast</span><span class="token operator">::</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token comment">/* ... */</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 创建播客...</span></span>
<span class="line"></span>
<span class="line">        <span class="token class-name static-context">ProcessPodcast</span><span class="token operator">::</span><span class="token function">dispatchSync</span><span class="token punctuation">(</span><span class="token variable">$podcast</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/podcasts'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="作业和数据库事务" tabindex="-1"><a class="header-anchor" href="#作业和数据库事务"><span>作业和数据库事务</span></a></h3>
<p>在数据库事务中调度作业是完全可以的，但你应该特别注意确保你的作业实际上能够成功执行。在事务中调度作业时，有可能作业在父事务提交之前就被工作器处理了。当这种情况发生时，你在数据库事务期间对模型或数据库记录所做的任何更新可能还没有反映在数据库中。此外，在事务中创建的任何模型或数据库记录可能还不存在于数据库中。</p>
<p>幸运的是，Laravel 提供了几种方法来解决这个问题。首先，你可以在队列连接的配置数组中设置 <code v-pre>after_commit</code> 连接选项：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token string single-quoted-string">'redis'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'driver'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'redis'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line">    <span class="token string single-quoted-string">'after_commit'</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当 <code v-pre>after_commit</code> 选项为 <code v-pre>true</code>, 你可以在数据库事务中调度作业；但是，Laravel 会等到打开的父数据库事务提交后再实际调度作业。当然，如果目前没有开启的数据库事务，作业将被立即调度。</p>
<p>如果事务因在事务期间发生的异常而回滚，那么在该事务期间调度的作业将被丢弃。</p>
<blockquote>
<p>[!NOTE]<br>
将 <code v-pre>after_commit</code> 配置选项设置为 <code v-pre>true</code> 还会导致任何排队的事件监听器、邮件、通知和广播事件在所有打开的数据库事务提交后被调度。</p>
</blockquote>
<h4 id="内联指定提交调度行为" tabindex="-1"><a class="header-anchor" href="#内联指定提交调度行为"><span>内联指定提交调度行为</span></a></h4>
<p>如果你没有将 <code v-pre>after_commit</code> 队列连接配置选项设置为 <code v-pre>true</code>，你仍然可以指定特定作业应在所有打开的数据库事务提交后被调度。为此，你可以将 <code v-pre>afterCommit</code> 方法链接到你的调度操作：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>ProcessPodcast</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">ProcessPodcast</span><span class="token operator">::</span><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token variable">$podcast</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">afterCommit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>类似地，如果 <code v-pre>after_commit</code> 配置选项被设置为 <code v-pre>true</code>，你可以指定特定作业应立即调度，无需等待任何打开的数据库事务提交：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">ProcessPodcast</span><span class="token operator">::</span><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token variable">$podcast</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">beforeCommit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="任务链" tabindex="-1"><a class="header-anchor" href="#任务链"><span>任务链</span></a></h3>
<p>任务链允许你指定一组应在主任务成功执行后按顺序运行的排队任务。如果序列中的一个任务失败，其余的任务将不会运行。要执行一个排队的任务链，你可以使用 <code v-pre>Bus</code> facade 提供的 <code v-pre>chain</code> 方法。Laravel 的命令总线是建立在排队作业调度之上的底层组件：：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>OptimizePodcast</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>ProcessPodcast</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>ReleasePodcast</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Bus</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Bus</span><span class="token operator">::</span><span class="token function">chain</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">ProcessPodcast</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">OptimizePodcast</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">ReleasePodcast</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>除了链式调用作业类实例，你还可以链式闭包：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Bus</span><span class="token operator">::</span><span class="token function">chain</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">ProcessPodcast</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">OptimizePodcast</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token class-name static-context">Podcast</span><span class="token operator">::</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token comment">/* ... */</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>注意</strong><br>
在任务中使用 <code v-pre>$this-&gt;delete()</code> 方法删除任务不会阻止链式任务的处理。只有当链中的任务失败时，链才会停止执行。</p>
</blockquote>
<h4 id="链式连接-队列" tabindex="-1"><a class="header-anchor" href="#链式连接-队列"><span>链式连接 &amp; 队列</span></a></h4>
<p>如果要指定链式任务应使用的连接和队列，可以使用 <code v-pre>onConnection</code> 和 <code v-pre>onQueue</code> 方法。这些方法指定应使用的队列连接和队列名称，除非为排队任务显式分配了不同的连接 / 队列：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Bus</span><span class="token operator">::</span><span class="token function">chain</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">ProcessPodcast</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">OptimizePodcast</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">ReleasePodcast</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onConnection</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'redis'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onQueue</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'podcasts'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="向链中添加任务" tabindex="-1"><a class="header-anchor" href="#向链中添加任务"><span>向链中添加任务</span></a></h4>
<p>有时，你可能需要从链中的另一个任务内向现有的任务链前置或后置添加任务。你可以使用 <code v-pre>prependToChain</code> 和 <code v-pre>appendToChain</code> 方法来实现这一点：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 执行任务。</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">handle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// 前置到当前链，在当前任务之后立即运行任务...</span></span>
<span class="line">    <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">prependToChain</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">TranscribePodcast</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// 后置到当前链，在链末尾运行任务...</span></span>
<span class="line">    <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">appendToChain</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">TranscribePodcast</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="链式失败" tabindex="-1"><a class="header-anchor" href="#链式失败"><span>链式失败</span></a></h4>
<p>在链式任务中，你可以使用 <code v-pre>catch</code> 方法来指定一个闭包，该闭包在链中的任务失败时被调用。给定的回调将接收导致任务失败的 <code v-pre>Throwable</code> 实例：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Bus</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Throwable</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Bus</span><span class="token operator">::</span><span class="token function">chain</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">ProcessPodcast</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">OptimizePodcast</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">ReleasePodcast</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Throwable</span> <span class="token variable">$e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 链中的某个任务失败了...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>警告</strong><br>
由于链回调被序列化并在稍后由 Laravel 队列执行，因此你不应在链回调中使用 <code v-pre>$this</code> 变量。</p>
</blockquote>
<h3 id="自定义队列连接" tabindex="-1"><a class="header-anchor" href="#自定义队列连接"><span>自定义队列连接</span></a></h3>
<h4 id="分发到特定队列" tabindex="-1"><a class="header-anchor" href="#分发到特定队列"><span>分发到特定队列</span></a></h4>
<p>通过将任务推送到不同的队列，你可以「分类」你的队列任务，甚至可以优先分配多少个 worker 到各种队列。请记住，这并不会将任务推送到队列配置文件中定义的不同队列「连接」，而只是推送到单个连接内的特定队列。要指定队列，在分发任务时使用 <code v-pre>onQueue</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>ProcessPodcast</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Podcast</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>RedirectResponse</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PodcastController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 存储一个新的播客。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">store</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">RedirectResponse</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$podcast</span> <span class="token operator">=</span> <span class="token class-name static-context">Podcast</span><span class="token operator">::</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token comment">/* ... */</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">//  创建播客...</span></span>
<span class="line"></span>
<span class="line">        <span class="token class-name static-context">ProcessPodcast</span><span class="token operator">::</span><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token variable">$podcast</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onQueue</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'processing'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/podcasts'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>或者，你可以在任务的构造函数中调用 <code v-pre>onQueue</code> 方法来指定任务的队列：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Jobs</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"> <span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Bus<span class="token punctuation">\</span>Queueable</span><span class="token punctuation">;</span></span>
<span class="line"> <span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>ShouldQueue</span><span class="token punctuation">;</span></span>
<span class="line"> <span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Foundation<span class="token punctuation">\</span>Bus<span class="token punctuation">\</span>Dispatchable</span><span class="token punctuation">;</span></span>
<span class="line"> <span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>InteractsWithQueue</span><span class="token punctuation">;</span></span>
<span class="line"> <span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>SerializesModels</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">ProcessPodcast</span> <span class="token keyword">implements</span> <span class="token class-name">ShouldQueue</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">use</span> <span class="token package">Dispatchable</span><span class="token punctuation">,</span> InteractsWithQueue<span class="token punctuation">,</span> Queueable<span class="token punctuation">,</span> SerializesModels<span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     *  创建一个新的任务实例。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">__construct</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">onQueue</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'processing'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="调度到特定连接" tabindex="-1"><a class="header-anchor" href="#调度到特定连接"><span>调度到特定连接</span></a></h4>
<p>如果你的应用与多个队列连接交互，你可以使用 <code v-pre>onConnection</code> 方法来指定任务应推送到的连接：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>ProcessPodcast</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Podcast</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>RedirectResponse</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PodcastController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 存储一个新的播客。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">store</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">RedirectResponse</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$podcast</span> <span class="token operator">=</span> <span class="token class-name static-context">Podcast</span><span class="token operator">::</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token comment">/* ... */</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 创建播客...</span></span>
<span class="line"></span>
<span class="line">        <span class="token class-name static-context">ProcessPodcast</span><span class="token operator">::</span><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token variable">$podcast</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onConnection</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'sqs'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/podcasts'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你可以链式调用 <code v-pre>onConnection</code> 和 <code v-pre>onQueue</code> 方法来指定任务的连接和队列：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">ProcessPodcast</span><span class="token operator">::</span><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token variable">$podcast</span><span class="token punctuation">)</span></span>
<span class="line">              <span class="token operator">-></span><span class="token function">onConnection</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'sqs'</span><span class="token punctuation">)</span></span>
<span class="line">              <span class="token operator">-></span><span class="token function">onQueue</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'processing'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>或者，你可以在任务的构造函数中调用 <code v-pre>onConnection</code> 方法来指定任务的连接：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Jobs</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"> <span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Bus<span class="token punctuation">\</span>Queueable</span><span class="token punctuation">;</span></span>
<span class="line"> <span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>ShouldQueue</span><span class="token punctuation">;</span></span>
<span class="line"> <span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Foundation<span class="token punctuation">\</span>Bus<span class="token punctuation">\</span>Dispatchable</span><span class="token punctuation">;</span></span>
<span class="line"> <span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>InteractsWithQueue</span><span class="token punctuation">;</span></span>
<span class="line"> <span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>SerializesModels</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">ProcessPodcast</span> <span class="token keyword">implements</span> <span class="token class-name">ShouldQueue</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">use</span> <span class="token package">Dispatchable</span><span class="token punctuation">,</span> InteractsWithQueue<span class="token punctuation">,</span> Queueable<span class="token punctuation">,</span> SerializesModels<span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 创建一个新的作业实例。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">__construct</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">onConnection</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'sqs'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="指定最大任务尝试-次数-超时值" tabindex="-1"><a class="header-anchor" href="#指定最大任务尝试-次数-超时值"><span>指定最大任务尝试 次数/ 超时值</span></a></h3>
<h4 id="最大尝试次数" tabindex="-1"><a class="header-anchor" href="#最大尝试次数"><span>最大尝试次数</span></a></h4>
<p>如果你的队列任务遇到错误，你可能不希望它无限期地重试。因此，Laravel 提供了多种方法来指定任务可以尝试的次数或持续时间。</p>
<p>指定作业可能尝试的最大次数的一种方法是通过 Artisan 命令行的 <code v-pre>--tries</code> 开关。这将适用于调度作业的所有任务，除非正在处理的任务指定了它最大尝试次数：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:work <span class="token parameter variable">--tries</span><span class="token operator">=</span><span class="token number">3</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>如果一个任务超过其最大尝试次数，它将被视为「失败」的任务。有关处理失败任务的更多信息，请查看<a href="#dealing-with-failed-jobs">处理失败队列</a>。如果给 <code v-pre>queue:work</code> 命令提供了 <code v-pre>--tries=0</code>，任务将无限次重试。</p>
<p>你可以采取更细粒度的方法，通过在任务类本身定义任务可以尝试的最大次数。如果在任务上指定了最大尝试次数，它将优先于命令行上提供的 <code v-pre>--tries</code> 值：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Jobs</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">ProcessPodcast</span> <span class="token keyword">implements</span> <span class="token class-name">ShouldQueue</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 任务可尝试的次数</span>
<span class="line">     *</span>
<span class="line">     * <span class="token keyword">@var</span> <span class="token class-name"><span class="token keyword">int</span></span></span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token variable">$tries</span> <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你需要对特定任务的最大尝试次数进行动态控制，你可以在作业上定义一个 <code v-pre>tries</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line">  * 确定任务可以尝试的次数。</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">tries</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">int</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token number">5</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="基于时间的尝试" tabindex="-1"><a class="header-anchor" href="#基于时间的尝试"><span>基于时间的尝试</span></a></h4>
<p>作为定义任务在失败前可尝试次数的替代方式，你可以定义一个任务应该超时的时间。这允许在给定时间范围内任意次数地尝试任务。要定义任务超时的时间，请在任务类中添加一个 <code v-pre>retryUntil</code> 方法。此方法应该返回一个 <code v-pre>DateTime</code> 实例：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">DateTime</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line">* 确定任务应当超时的时间。</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">retryUntil</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">DateTime</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">addMinutes</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>注意</strong><br>
你也可以在<a href="https://learnku.com/docs/laravel/11.x/eventsmd#queued-event-listeners" target="_blank" rel="noopener noreferrer">队列事件监听器</a>上定义 <code v-pre>tries</code> 属性或 <code v-pre>retryUntil</code> 方法。</p>
</blockquote>
<h4 id="最大异常数" tabindex="-1"><a class="header-anchor" href="#最大异常数"><span>最大异常数</span></a></h4>
<p>有时你可能希望指定一个任务可以尝试多次，但如果重试是由给定数量的未处理异常触发的（而不是直接被 <code v-pre>release</code> 方法释放的），应该失败。为此，你可以在任务类中定义一个 <code v-pre>maxExceptions</code> 属性：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Jobs</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Redis</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">ProcessPodcast</span> <span class="token keyword">implements</span> <span class="token class-name">ShouldQueue</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 可以尝试任务的次数</span>
<span class="line">     *</span>
<span class="line">     * <span class="token keyword">@var</span> <span class="token class-name"><span class="token keyword">int</span></span></span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token variable">$tries</span> <span class="token operator">=</span> <span class="token number">25</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 失败前允许的最大未处理异常数</span>
<span class="line">     *</span>
<span class="line">     * <span class="token keyword">@var</span> <span class="token class-name"><span class="token keyword">int</span></span></span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token variable">$maxExceptions</span> <span class="token operator">=</span> <span class="token number">3</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 执行</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">handle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token class-name static-context">Redis</span><span class="token operator">::</span><span class="token function">throttle</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'key'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">allow</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">every</span><span class="token punctuation">(</span><span class="token number">60</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token comment">// 获得锁，处理播客...</span></span>
<span class="line">        <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token comment">// 无法获取锁...</span></span>
<span class="line">            <span class="token keyword">return</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">release</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在此示例中，如果应用程序无法获得 Redis 锁，则该任务将在 10 秒后被释放，并将继续重试最多 25 次。但是，如果任务抛出三个未处理的异常，则任务将失败。</p>
<h4 id="超时" tabindex="-1"><a class="header-anchor" href="#超时"><span>超时</span></a></h4>
<p>通常，你大致知道你的排队任务需要多长时间。因此，Laravel 允许你指定一个「超时」值。默认情况下，超时值为 60 秒。如果任务的处理时间超过超时值指定的秒数，处理任务的工作进程将退出并报错。通常，工作进程将由服务器上配置的<a href="#supervisor-configuration">进程管理器</a>自动重启。</p>
<p>任务可以运行的最大秒数可以使用 Artisan 命令行上的 <code v-pre>--timeout</code> 开关指定：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:work <span class="token parameter variable">--timeout</span><span class="token operator">=</span><span class="token number">30</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>如果任务因不断超时超过其最大尝试次数，它将被标记为失败。</p>
<p>你还可以在任务类本身定义任务允许运行的最大秒数。如果在任务上指定了超时时间，它将优先于命令行上指定的任何超时时间：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Jobs</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">ProcessPodcast</span> <span class="token keyword">implements</span> <span class="token class-name">ShouldQueue</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 在超时之前任务可以运行的秒数.</span>
<span class="line">     *</span>
<span class="line">     * <span class="token keyword">@var</span> <span class="token class-name"><span class="token keyword">int</span></span></span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token variable">$timeout</span> <span class="token operator">=</span> <span class="token number">120</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>有时，诸如 socket 或外部 HTTP 连接之类的 IO 阻塞过程可能不会遵守你指定的超时。因此，在使用这些功能时，你应该始终尝试使用他们的 API 来指定超时时间。例如，当使用 Guzzle 时，你应该总是指定连接和请求超时值。</p>
<blockquote>
<p><strong>注意</strong><br>
必须安装 PHP <code v-pre>pcntl</code> 扩展才能指定任务超时。此外，任务的「超时」值应始终小于其<a href="#job-expiration">「任务到期」</a>值。否则，可能在任务实际完成执行或超时前，任务就会被重试。</p>
</blockquote>
<h4 id="超时失败" tabindex="-1"><a class="header-anchor" href="#超时失败"><span>超时失败</span></a></h4>
<p>如果你希望在超时时将任务标记为 <a href="#dealing-with-failed-job">failed</a>，可以在任务类上定义 <code v-pre>$failOnTimeout</code> 属性：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 标示是否应在超时时标记为失败</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@var</span> <span class="token class-name"><span class="token keyword">bool</span></span></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token variable">$failOnTimeout</span> <span class="token operator">=</span> <span class="token constant boolean">true</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="错误处理" tabindex="-1"><a class="header-anchor" href="#错误处理"><span>错误处理</span></a></h3>
<p>如果在处理任务时抛出异常，任务将自动被释放回队列，以便稍后再尝试。只要应用程序允许，任务将继续发布，直到尝试达到你的应用程序允许的最大次数为止。最大尝试次数由 <code v-pre>queue:work</code> Artisan 命令上使用的 <code v-pre>--tries</code> 开关定义。或者，最大尝试次数可以在任务类本身上定义。有关运行队列工作器的更多信息<a href="#running-the-queue-worker">可以在下面找到</a>。</p>
<h4 id="手动释放任务" tabindex="-1"><a class="header-anchor" href="#手动释放任务"><span>手动释放任务</span></a></h4>
<p>有时你可能希望手动将任务释放回队列，以便稍后再次尝试。你可以通过调用 <code v-pre>release</code> 方法来实现这一点：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 执行任务</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">handle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"></span>
<span class="line">    <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">release</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>默认情况下，<code v-pre>release</code> 方法会将任务立即释放回队列。但是，你可以通过向 <code v-pre>release</code> 方法传递一个整数或日期实例来指示队列，使任务在指定的秒数之后才能进行处理：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$this</span><span class="token operator">-></span><span class="token function">release</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$this</span><span class="token operator">-></span><span class="token function">release</span><span class="token punctuation">(</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">addSeconds</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="手动标记任务失败" tabindex="-1"><a class="header-anchor" href="#手动标记任务失败"><span>手动标记任务失败</span></a></h4>
<p>有时你可能需要手动将任务标记为「失败」。为此，你可以调用 <code v-pre>fail</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 执行作业</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">handle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"></span>
<span class="line">    <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">fail</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你捕获了一个异常，你想直接将你的任务标记为失败，你可以将异常传递给 <code v-pre>fail</code> 方法。 或者，为方便起见，你可以传递一个字符串来表示错误异常信息：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$this</span><span class="token operator">-></span><span class="token function">fail</span><span class="token punctuation">(</span><span class="token variable">$exception</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$this</span><span class="token operator">-></span><span class="token function">fail</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Something went wrong.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>技巧</strong><br>
有关失败任务的更多信息，请查看 <a href="#dealing-with-failed-jobs">处理任务失败的文档</a>。</p>
</blockquote>
<h2 id="任务批处理" tabindex="-1"><a class="header-anchor" href="#任务批处理"><span>任务批处理</span></a></h2>
<p>Laravel 的任务批处理功能允许你轻松执行一批作业，然后在任务批次完成执行后执行某些操作。在开始之前，你应该创建一个数据库迁移来构建一个表，该表将包含有关任务批次的元信息，例如它们的完成百分比。可以使用 <code v-pre>make:queue-batches-table</code> Artisan 命令来生成这个迁移：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan make:queue-batches-table</span>
<span class="line"></span>
<span class="line">php artisan migrate</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="定义可批处理任务" tabindex="-1"><a class="header-anchor" href="#定义可批处理任务"><span>定义可批处理任务</span></a></h3>
<p>要定义可批处理的任务，你应该像平常一样<a href="#creating-jobs">创建一个可排队的任务</a> ；但是，你应该将 <code v-pre>Illuminate\Bus\Batchable</code> trait 添加到任务类。这个 trait 提供了一个 <code v-pre>batch</code> 方法，可用于检索任务正在执行的当前批次：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Jobs</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Bus<span class="token punctuation">\</span>Batchable</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Bus<span class="token punctuation">\</span>Queueable</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>ShouldQueue</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Foundation<span class="token punctuation">\</span>Bus<span class="token punctuation">\</span>Dispatchable</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>InteractsWithQueue</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>SerializesModels</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">ImportCsv</span> <span class="token keyword">implements</span> <span class="token class-name">ShouldQueue</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">use</span> <span class="token package">Batchable</span><span class="token punctuation">,</span> Dispatchable<span class="token punctuation">,</span> InteractsWithQueue<span class="token punctuation">,</span> Queueable<span class="token punctuation">,</span> SerializesModels<span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 执行任务</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">handle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$this</span><span class="token operator">-></span><span class="token function">batch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cancelled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token comment">// 确定批次是否已取消...</span></span>
<span class="line"></span>
<span class="line">            <span class="token keyword">return</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 导入 CSV 文件的一部分...</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="调度批处理任务" tabindex="-1"><a class="header-anchor" href="#调度批处理任务"><span>调度批处理任务</span></a></h3>
<p>要调度一批作业，你应该使用 <code v-pre>Bus</code> facade 的 <code v-pre>batch</code> 方法。当然，批处理主要在与完成回调结合使用时才有用。因此，你可以使用 <code v-pre>then</code>、<code v-pre>catch</code> 和 <code v-pre>finally</code> 方法为批处理定义完成回调。这些回调在被调用时都将接收到一个 <code v-pre>Illuminate\Bus\Batch</code> 实例。在这个例子中，我们假设我们正在排队一批任务，每个任务处理 CSV 文件中给定数量的行：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>ImportCsv</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Bus<span class="token punctuation">\</span>Batch</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Bus</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Throwable</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$batch</span> <span class="token operator">=</span> <span class="token class-name static-context">Bus</span><span class="token operator">::</span><span class="token function">batch</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">ImportCsv</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">ImportCsv</span><span class="token punctuation">(</span><span class="token number">101</span><span class="token punctuation">,</span> <span class="token number">200</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">ImportCsv</span><span class="token punctuation">(</span><span class="token number">201</span><span class="token punctuation">,</span> <span class="token number">300</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">ImportCsv</span><span class="token punctuation">(</span><span class="token number">301</span><span class="token punctuation">,</span> <span class="token number">400</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">ImportCsv</span><span class="token punctuation">(</span><span class="token number">401</span><span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">before</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Batch</span> <span class="token variable">$batch</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 批处理已创建但尚未添加任何作业...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">progress</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Batch</span> <span class="token variable">$batch</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 单个作业已成功完成..</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Batch</span> <span class="token variable">$batch</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 所有作业都已成功完成...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Batch</span> <span class="token variable">$batch</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Throwable</span> <span class="token variable">$e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 检测到第一个批处理作业失败...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">finally</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Batch</span> <span class="token variable">$batch</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 批处理执行完毕...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">return</span> <span class="token variable">$batch</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>批处理的 ID 可以通过 <code v-pre>$batch-&gt;id</code> 属性访问，可用于 <a href="#inspecting-batches">查询 Laravel 命令总线</a> 以获取有关批次分派后的信息。</p>
<blockquote>
<p><strong>注意</strong><br>
由于批处理回调会被序列化并在稍后由 Laravel 队列执行，所以你不应该在回调中使用 <code v-pre>$this</code> 变量。此外，由于批处理作业是封装在数据库事务中的，所以不应该在作业中执行触发隐式提交的数据库语句。</p>
</blockquote>
<h4 id="命名批处理" tabindex="-1"><a class="header-anchor" href="#命名批处理"><span>命名批处理</span></a></h4>
<p>部分工具，如 Laravel Horizon 和 Laravel Telescope 可能会为命名的批处理提供更友好的调试信息。为了给批处理分配一个任意名称，你可以在定义批处理时调用 <code v-pre>name</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$batch</span> <span class="token operator">=</span> <span class="token class-name static-context">Bus</span><span class="token operator">::</span><span class="token function">batch</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Batch</span> <span class="token variable">$batch</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 所有任务都已成功完成...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Import CSV'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="批处理连接-队列" tabindex="-1"><a class="header-anchor" href="#批处理连接-队列"><span>批处理连接 &amp; 队列</span></a></h4>
<p>如果你想指定应用于批处理任务的连接和队列，你可以使用 <code v-pre>onConnection</code> 和 <code v-pre>onQueue</code> 方法。 所有批处理任务必须在相同的连接和队列中执行：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$batch</span> <span class="token operator">=</span> <span class="token class-name static-context">Bus</span><span class="token operator">::</span><span class="token function">batch</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Batch</span> <span class="token variable">$batch</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 所有任务均已成功完成...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onConnection</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'redis'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onQueue</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'imports'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="链式-批处理" tabindex="-1"><a class="header-anchor" href="#链式-批处理"><span>链式 ＆ 批处理</span></a></h3>
<p>你可以将一组<a href="#job-chaining">链式任务</a>定义在一个批处理中，方法是将链接的任务放在一个数组内。例如，我们可以并行执行两个任务链，并在两个任务链都完成处理后执行一个回调：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>ReleasePodcast</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>SendPodcastReleaseNotification</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Bus<span class="token punctuation">\</span>Batch</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Bus</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Bus</span><span class="token operator">::</span><span class="token function">batch</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token punctuation">[</span></span>
<span class="line">        <span class="token keyword">new</span> <span class="token class-name">ReleasePodcast</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token keyword">new</span> <span class="token class-name">SendPodcastReleaseNotification</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">[</span></span>
<span class="line">        <span class="token keyword">new</span> <span class="token class-name">ReleasePodcast</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token keyword">new</span> <span class="token class-name">SendPodcastReleaseNotification</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Batch</span> <span class="token variable">$batch</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>相反，你可以通过在链中定义批处理来在一个<a href="#job-chaining">链</a> 中运行一批任务。例如，你可以先运行一批任务来发布多个播客，然后运行一批任务来发送发布通知：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>FlushPodcastCache</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>ReleasePodcast</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>SendPodcastReleaseNotification</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Bus</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Bus</span><span class="token operator">::</span><span class="token function">chain</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">FlushPodcastCache</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token class-name static-context">Bus</span><span class="token operator">::</span><span class="token function">batch</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">        <span class="token keyword">new</span> <span class="token class-name">ReleasePodcast</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token keyword">new</span> <span class="token class-name">ReleasePodcast</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token class-name static-context">Bus</span><span class="token operator">::</span><span class="token function">batch</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">        <span class="token keyword">new</span> <span class="token class-name">SendPodcastReleaseNotification</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token keyword">new</span> <span class="token class-name">SendPodcastReleaseNotification</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="批量添加任务" tabindex="-1"><a class="header-anchor" href="#批量添加任务"><span>批量添加任务</span></a></h3>
<p>有些时候，批量向批处理中添加任务可能很有用。当你需要批量处理数千个任务时，这种模式非常好用，而这些任务在 Web 请求期间可能需要很长时间才能调度。因此，你可能希望调度初始批次的「加载器」任务，这些任务与更多任务相结合：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$batch</span> <span class="token operator">=</span> <span class="token class-name static-context">Bus</span><span class="token operator">::</span><span class="token function">batch</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">LoadImportBatch</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">LoadImportBatch</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">LoadImportBatch</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Batch</span> <span class="token variable">$batch</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// All jobs completed successfully...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Import Contacts'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在这个例子中，我们将使用 <code v-pre>LoadImportBatch</code> 任务为批处理添加其他任务。为此，我们可以对批处理实例使用 <code v-pre>add</code> 方法，该方法可以通过任务的 <code v-pre>batch</code> 方法访问：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>ImportContacts</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Collection</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 执行任务</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">handle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$this</span><span class="token operator">-></span><span class="token function">batch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cancelled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">batch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">add</span><span class="token punctuation">(</span><span class="token class-name static-context">Collection</span><span class="token operator">::</span><span class="token function">times</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">ImportContacts</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>注意</strong><br>
你只能将任务添加到当前任务所属的批处理中。</p>
</blockquote>
<h3 id="校验批处理" tabindex="-1"><a class="header-anchor" href="#校验批处理"><span>校验批处理</span></a></h3>
<p>为批处理完成后提供回调的 <code v-pre>Illuminate\Bus\Batch</code> 实例中具有多种属性和方法，可以帮助你与指定的批处理业务进行交互和检查：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token comment">// 批处理的UUID..</span></span>
<span class="line"><span class="token variable">$batch</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 批处理的名称（如果已经设置的话）...</span></span>
<span class="line"><span class="token variable">$batch</span><span class="token operator">-></span><span class="token property">name</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 分配给批处理的任务数量...</span></span>
<span class="line"><span class="token variable">$batch</span><span class="token operator">-></span><span class="token property">totalJobs</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 队列还没处理的任务数量...</span></span>
<span class="line"><span class="token variable">$batch</span><span class="token operator">-></span><span class="token property">pendingJobs</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 失败的任务数量...</span></span>
<span class="line"><span class="token variable">$batch</span><span class="token operator">-></span><span class="token property">failedJobs</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 到目前为止已经处理的任务数量...</span></span>
<span class="line"><span class="token variable">$batch</span><span class="token operator">-></span><span class="token function">processedJobs</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 批处理已经完成的百分比（0-100）...</span></span>
<span class="line"><span class="token variable">$batch</span><span class="token operator">-></span><span class="token function">progress</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 批处理是否已经完成执行...</span></span>
<span class="line"><span class="token variable">$batch</span><span class="token operator">-></span><span class="token function">finished</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 取消批处理的运行...</span></span>
<span class="line"><span class="token variable">$batch</span><span class="token operator">-></span><span class="token function">cancel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 批处理是否已经取消...</span></span>
<span class="line"><span class="token variable">$batch</span><span class="token operator">-></span><span class="token function">cancelled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="从路由返回批次" tabindex="-1"><a class="header-anchor" href="#从路由返回批次"><span>从路由返回批次</span></a></h4>
<p>所有 <code v-pre>Illuminate\Bus\Batch</code> 实例都是 JSON 可序列化的，这意味着你可以直接从应用程序的一个路由返回它们，以检索包含有关批处理的信息的 JSON 有效负载，包括其完成进度。这样可以方便地在应用程序的 UI 中显示有关批处理完成进度的信息。</p>
<p>要通过 ID 检索批次，你可以使用 <code v-pre>Bus</code> facade 的 <code v-pre>findBatch</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Bus</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Route</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/batch/{batchId}'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token keyword type-hint">string</span> <span class="token variable">$batchId</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token class-name static-context">Bus</span><span class="token operator">::</span><span class="token function">findBatch</span><span class="token punctuation">(</span><span class="token variable">$batchId</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="取消批次" tabindex="-1"><a class="header-anchor" href="#取消批次"><span>取消批次</span></a></h3>
<p>有时你可能需要取消给定批处理的执行。这可以通过调用 <code v-pre>Illuminate\Bus\Batch</code> 实例的 <code v-pre>cancel</code> 方法来完成：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 执行任务。</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">handle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$this</span><span class="token operator">-></span><span class="token property">user</span><span class="token operator">-></span><span class="token function">exceedsImportLimit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">batch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cancel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$this</span><span class="token operator">-></span><span class="token function">batch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cancelled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>正如你在前面的示例中可能已经注意到的那样，批处理任务通常应在继续执行之前确定其对应的批处理是否已被取消。但为了方便起见，你也可以为任务分配 <code v-pre>SkipIfBatchCancelled</code> <a href="#job-middleware">中间件</a>。顾名思义，这个中间件会指示 Laravel，如果其对应的批处理已被取消，则不处理任务：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>SkipIfBatchCancelled</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 获取任务应通过的中间件。</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">array</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token keyword">new</span> <span class="token class-name">SkipIfBatchCancelled</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="批处理失败" tabindex="-1"><a class="header-anchor" href="#批处理失败"><span>批处理失败</span></a></h3>
<p>当批处理任务失败时，将调用 <code v-pre>catch</code> 回调（如果已分配）。此回调仅针对批处理中失败的第一个任务调用。</p>
<h4 id="允许失败" tabindex="-1"><a class="header-anchor" href="#允许失败"><span>允许失败</span></a></h4>
<p>当批处理中的任务失败时，Laravel 会自动将批处理标记为「已取消」。如果你愿意，你可以禁用此行为，以便任务失败不会自动将批处理标记为已取消。这可以通过在调度批处理时调用 <code v-pre>allowFailures</code> 方法来实现：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$batch</span> <span class="token operator">=</span> <span class="token class-name static-context">Bus</span><span class="token operator">::</span><span class="token function">batch</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Batch</span> <span class="token variable">$batch</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 所有任务均已成功完成...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">allowFailures</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="重试失败的批处理任务" tabindex="-1"><a class="header-anchor" href="#重试失败的批处理任务"><span>重试失败的批处理任务</span></a></h4>
<p>为了方便起见，Laravel 提供了一个 <code v-pre>queue:retry-batch</code> Artisan 命令，允许你轻松地重试给定批处理的所有失败作业。<code v-pre>queue:retry-batch</code> 命令接受要重试其失败任务的批处理的 UUID：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:retry-batch 32dbc76c-4f82-4749-b610-a639fe0099b5</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="修剪批处理" tabindex="-1"><a class="header-anchor" href="#修剪批处理"><span>修剪批处理</span></a></h3>
<p>如果不进行修剪，<code v-pre>job_batches</code> 表可以非常快速地积累记录。为了缓解这种情况，你应该 <a href="https://learnku.com/docs/laravel/11.x/schedulingmd" target="_blank" rel="noopener noreferrer">schedule</a> <code v-pre>queue:prune-batches</code> Artisan 命令每天运行：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Schedule</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Schedule</span><span class="token operator">::</span><span class="token function">command</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'queue:prune-batches'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">daily</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>默认情况下，所有已完成且超过 24 小时的批处理都会被修剪。在调用命令时你可以使用 <code v-pre>hours</code> 选项来决定保留批处理数据的时间长短。例如，以下命令将删除所有 48 小时前完成的批处理：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Schedule</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Schedule</span><span class="token operator">::</span><span class="token function">command</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'queue:prune-batches --hours=48'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">daily</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>有时，你的 <code v-pre>jobs_batches</code> 表可能会积累从未成功完成的批处理记录，例如未成功重试的失败任务的批处理。你可以指示 <code v-pre>queue:prune-batches</code> 命令使用 <code v-pre>unfinished</code> 选项来修剪这些未完成的批处理记录：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Schedule</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Schedule</span><span class="token operator">::</span><span class="token function">command</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'queue:prune-batches --hours=48 --unfinished=72'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">daily</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>同样，你的 <code v-pre>jobs_batches</code> 表也可能积累已取消批处理的批处理记录。你可以指示 <code v-pre>queue:prune-batches</code> 命令使用 <code v-pre>cancelled</code> 选项来修剪这些已取消批处理记录：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Schedule</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Schedule</span><span class="token operator">::</span><span class="token function">command</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'queue:prune-batches --hours=48 --cancelled=72'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">daily</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="在-dynamodb-中存储批处理" tabindex="-1"><a class="header-anchor" href="#在-dynamodb-中存储批处理"><span>在 DynamoDB 中存储批处理</span></a></h3>
<p>Laravel 还支持在 <a href="https://aws.amazon.com/dynamodb" target="_blank" rel="noopener noreferrer">DynamoDB</a> 中存储批处理元信息，而不是在关系数据库中。不过，你需要手动创建一个 DynamoDB 表来存储所有的批处理记录。</p>
<p>通常情况下，此表应命名为 <code v-pre>job_batches</code>，但你应基于应用程序 <code v-pre>queue</code> 配置文件中的 <code v-pre>queue.batching.table</code> 配置值来命名此表。</p>
<h4 id="dynamodb-批处理表配置" tabindex="-1"><a class="header-anchor" href="#dynamodb-批处理表配置"><span>DynamoDB 批处理表配置</span></a></h4>
<p><code v-pre>job_batches</code> 表应具有一个名为 <code v-pre>application</code> 的字符串主分区键和一个名为 <code v-pre>id</code> 的字符串主排序键。键中的 <code v-pre>application</code> 部分将包含你的应用程序名称，该名称由应用程序 <code v-pre>app</code> 配置文件中的 <code v-pre>name</code> 配置值定义。由于应用程序名称是 DynamoDB 表键的一部分，因此可以使用同一张表来存储多个 Laravel 应用程序的任务批处理。</p>
<p>此外，如果你希望利用 <a href="#pruning-batches-in-dynamodb">自动批处理修剪</a> 功能，你可以为表定义 <code v-pre>ttl</code> 属性。</p>
<h4 id="dynamodb-配置" tabindex="-1"><a class="header-anchor" href="#dynamodb-配置"><span>DynamoDB 配置</span></a></h4>
<p>接下来，安装 AWS SDK，以便你的 Laravel 应用程序可以与 Amazon DynamoDB 通信：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line"><span class="token function">composer</span> require aws/aws-sdk-php</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>然后，将 <code v-pre>queue.batching.driver</code> 配置选项的值设置为 <code v-pre>dynamodb</code>。此外，你应在 <code v-pre>batching</code> 配置数组中定义 <code v-pre>key</code>、<code v-pre>secret</code> 和 <code v-pre>region</code> 配置选项。这些选项将用于认证 AWS。使用 <code v-pre>dynamodb</code> 驱动时不需要 <code v-pre>queue.batching.database</code> 配置选项：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token string single-quoted-string">'batching'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'driver'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'QUEUE_FAILED_DRIVER'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'dynamodb'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'key'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'AWS_ACCESS_KEY_ID'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'secret'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'AWS_SECRET_ACCESS_KEY'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'region'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'AWS_DEFAULT_REGION'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'us-east-1'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'table'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'job_batches'</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="在-dynamodb-中修剪批次" tabindex="-1"><a class="header-anchor" href="#在-dynamodb-中修剪批次"><span>在 DynamoDB 中修剪批次</span></a></h4>
<p>在使用 <a href="https://aws.amazon.com/dynamodb" target="_blank" rel="noopener noreferrer">DynamoDB</a> 存储作业批次信息时，常规用于修剪关系数据库中存储批次的命令将无法适用。相反，你以利用 <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html" target="_blank" rel="noopener noreferrer">DynamoDB 内置的 TTL 功能</a> 来自动删除旧批次的记录。</p>
<p>如果你在 DynamoDB 表中定义了 <code v-pre>ttl</code> 属性，你可以定义配置参数指导 Laravel 如何修剪批次记录。配置值 <code v-pre>queue.batching.ttl_attribute</code> 定义持有 TTL 的属性名称，而 <code v-pre>queue.batching.ttl</code> 配置值定义批次记录可以从 DynamoDB 表中删除的秒数，相对于记录最后一次更新的时间：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token string single-quoted-string">'batching'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'driver'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'QUEUE_FAILED_DRIVER'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'dynamodb'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'key'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'AWS_ACCESS_KEY_ID'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'secret'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'AWS_SECRET_ACCESS_KEY'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'region'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'AWS_DEFAULT_REGION'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'us-east-1'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'table'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'job_batches'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'ttl_attribute'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'ttl'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'ttl'</span> <span class="token operator">=></span> <span class="token number">60</span> <span class="token operator">*</span> <span class="token number">60</span> <span class="token operator">*</span> <span class="token number">24</span> <span class="token operator">*</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token comment">// 7 days...</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="队列闭包" tabindex="-1"><a class="header-anchor" href="#队列闭包"><span>队列闭包</span></a></h2>
<p>除了发送任务类到队列外，你还可以发送闭包。这对于需要在当前请求周期之外执行的快速、简单的任务非常有用。当将闭包发送到队列时，闭包的代码内容是加密签名的，防止在传输中被修改：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$podcast</span> <span class="token operator">=</span> <span class="token class-name class-name-fully-qualified static-context">App<span class="token punctuation">\</span>Podcast</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">use</span> <span class="token punctuation">(</span><span class="token variable">$podcast</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$podcast</span><span class="token operator">-></span><span class="token function">publish</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>使用 <code v-pre>catch</code> 方法，你可以提供一个闭包，该闭包在队列闭包在用完队列的<a href="#max-job-attempts-and-timeout">配置重试次数</a>后未能成功完成时执行：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Throwable</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">use</span> <span class="token punctuation">(</span><span class="token variable">$podcast</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$podcast</span><span class="token operator">-></span><span class="token function">publish</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Throwable</span> <span class="token variable">$e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// This job has failed...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>注意</strong><br>
由于 <code v-pre>catch</code> 回调由 Laravel 队列稍后序列化并执行，因此你不应在 <code v-pre>catch</code> 回调中使用 <code v-pre>$this</code> 变量</p>
</blockquote>
<h2 id="running-the-queue-worker" tabindex="-1"><a class="header-anchor" href="#running-the-queue-worker"><span>Running the Queue Worker</span></a></h2>
<h3 id="运行队列工作者" tabindex="-1"><a class="header-anchor" href="#运行队列工作者"><span>运行队列工作者</span></a></h3>
<h4 id="queue-work-命令" tabindex="-1"><a class="header-anchor" href="#queue-work-命令"><span><code v-pre>queue:work</code> 命令</span></a></h4>
<p>Laravel 包含了一个 Artisan 命令，可以启动一个队列进程并处理新推送到队列的作业。你可以使用 <code v-pre>queue:work</code> Artisan 命令运行任务进程。请注意一旦 <code v-pre>queue:work</code> 命令启动，它将持续运行直到被手动停止或关闭终端：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:work</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p><strong>技巧</strong><br>
为了让 <code v-pre>queue:work</code> 进程在后台永久运行，你应该使用进程监控工具如 <a href="#supervisor-configuration">Supervisor</a>来确保队列任务进程不会停止运行。</p>
</blockquote>
<p>如果你希望处理的任务 ID 包含在命令的输出中，则可以在调用 <code v-pre>queue:work</code> 命令时包含 <code v-pre>-v</code> 标志：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:work <span class="token parameter variable">-v</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>请记住，队列任务工作者是长期存在的进程，并并将启动的应用程序状态存储在内存中。因此，它们在启动后不会注意到代码库的变化。因此，在部署过程中，记得<a href="#queue-workers-and-deployment">重启你的任务队列进程</a>。此外，记住应用程序创建或修改的任何静态状态都不会自动在任务之间重置。</p>
<p>或者，你可以运行 <code v-pre>queue:listen</code> 命令。使用 <code v-pre>queue:listen</code> 命令时，当你想重新加载已更新的代码或重置应用状态时，不需要手动重启工作进程；但是，与 <code v-pre>queue:work</code> 命令相比，该命令效率要低得多：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:listen</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h4 id="运行多个队列进程" tabindex="-1"><a class="header-anchor" href="#运行多个队列进程"><span>运行多个队列进程</span></a></h4>
<p>要将多个 worker 分配到一个队列并同时处理任务，你应该简单地启动多个 queue:work 进程。 这可以通过终端中的多个选项卡在本地完成，也可以使用流程管理器的配置设置在生产环境中完成。 使用 Supervisor 时，你可以使用 numprocs 配置值。</p>
<p>要给队列分配多个工作进程并同时处理任务，你只需启动多个 <code v-pre>queue:work</code> 进程即可。在本地可以通过在终端中打开多个标签页来完成，在生产环境中可以使用你的进程管理器的配置设置完成。<a href="#supervisor-configuration">在使用 Supervisor 时</a>，你可以使用 <code v-pre>numprocs</code> 配置值。</p>
<h4 id="指定连接-队列" tabindex="-1"><a class="header-anchor" href="#指定连接-队列"><span>指定连接 &amp; 队列</span></a></h4>
<p>你还可以指定工作进程应使用的队列连接。传递给 <code v-pre>work</code> 命令的连接名称应对应于你的 <code v-pre>config/queue.php</code> 配置文件中定义的连接之一：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:work redis</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>默认情况下，<code v-pre>queue:work</code> 命令仅处理给定连接上的默认队列的任务。但是，你可以通过仅处理给定连接上的特定队列来进一步自定义队列工作者。例如，如果你的所有电子邮件都在你的 <code v-pre>redis</code> 队列连接的 <code v-pre>emails</code> 队列中处理，那么你可以发出以下命令来启动一个只处理该队列的工作进程：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:work redis <span class="token parameter variable">--queue</span><span class="token operator">=</span>emails</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h4 id="处理指定数量的任务" tabindex="-1"><a class="header-anchor" href="#处理指定数量的任务"><span>处理指定数量的任务</span></a></h4>
<p><code v-pre>--once</code> 选项可用于指定进程仅处理队列中的单个任务</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:work <span class="token parameter variable">--once</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p><code v-pre>--max-jobs</code> 选项可以用于指示工作进程处理给定数量的任务然后退出。结合 <a href="#supervisor-configuration">Supervisor</a>使用时，这个选项可能很有用，因为你的工作进程会在处理给定数量的作业后自动重启，释放可能积累的任何内存：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:work --max-jobs<span class="token operator">=</span><span class="token number">1000</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h4 id="处理所有排队的任务然后退出" tabindex="-1"><a class="header-anchor" href="#处理所有排队的任务然后退出"><span>处理所有排队的任务然后退出</span></a></h4>
<p><code v-pre>--stop-when-empty</code> 选项可以用于指示进程处理所有任务然后优雅地退出。当在 Docker 容器中处理 Laravel 队列时，如果你希望在队列为空后关闭容器，这个选项可能会很有用：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:work --stop-when-empty</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h4 id="在给定的秒数内处理任务" tabindex="-1"><a class="header-anchor" href="#在给定的秒数内处理任务"><span>在给定的秒数内处理任务</span></a></h4>
<p><code v-pre>--max-time</code> 选项可用于指示进程给定的秒数内处理任务。结合 <a href="#supervisor-configuration">Supervisor</a> 使用时，这个选项可能很有用，因为你的进程会在处理作业指定时间后自动重启，释放可能积累的任何内存：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line"><span class="token comment"># 处理进程一小时，然后退出...</span></span>
<span class="line">php artisan queue:work --max-time<span class="token operator">=</span><span class="token number">3600</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="进程睡眠时间" tabindex="-1"><a class="header-anchor" href="#进程睡眠时间"><span>进程睡眠时间</span></a></h4>
<p>当队列中有任务可用时，程将继续处理任务，而不会在它们之间产生延迟。然而，如果队列上没有可用的任务，<code v-pre>sleep</code> 选项将决定进程「休眠」 多少秒。当然，在休眠时，进程不会处理任何新任务：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:work <span class="token parameter variable">--sleep</span><span class="token operator">=</span><span class="token number">3</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h4 id="维护模式-队列" tabindex="-1"><a class="header-anchor" href="#维护模式-队列"><span>维护模式 ＆ 队列</span></a></h4>
<p>当应用程序处于 <a href="https://learnku.com/docs/laravel/11.x/configurationmd#maintenance-mode" target="_blank" rel="noopener noreferrer">维护模式</a> 时，不会处理任何队列任务。一旦应用程序退出维护模式，任务将继续像往常一样处理。</p>
<p>如果你希望在维护模式启用时强制队列进程处理任务，你可以使用 <code v-pre>--force</code> 选项：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:work <span class="token parameter variable">--force</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h4 id="资源注意事项" tabindex="-1"><a class="header-anchor" href="#资源注意事项"><span>资源注意事项</span></a></h4>
<p>守护进程队列在处理每个任务前并不会「重启」框架。因此，在每个任务完成后，应当释放任何占用的大量资源。例如，如果你使用 GD 库进行图像处理，完成图像处理后，应通过调用 <code v-pre>imagedestroy</code> 来释放内存，</p>
<h3 id="队列优先级" tabindex="-1"><a class="header-anchor" href="#队列优先级"><span>队列优先级</span></a></h3>
<p>有时你可能希望优先处理队列的处理方式。例如，在 <code v-pre>config/queue.php</code> 配置文件中，你可能会将 <code v-pre>redis</code> 连接的默认 <code v-pre>queue</code> 设置为 <code v-pre>low</code>。但是，偶尔你可能希望将任务推送到 <code v-pre>high</code> 优先级队列，如下所示：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Job</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onQueue</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'high'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>要启动一个进程以确保所有 <code v-pre>high</code> 队列任务在继续执行 <code v-pre>low</code> 队列上的任何任务之前都得到处理，请请将队列名称的逗号分隔列表传递给 <code v-pre>work</code> 命令：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:work <span class="token parameter variable">--queue</span><span class="token operator">=</span>high,low</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="队列进程-部署" tabindex="-1"><a class="header-anchor" href="#队列进程-部署"><span>队列进程 &amp; 部署</span></a></h3>
<p>由于队列任务是长期存在的进程，如果不重新启动，他们不会注意到代码的更改。因此，使用队列任务部署应用程序的最简单方法是在部署过程中重新启动任务。你可以通过发出 <code v-pre>queue:restart</code> 命令优雅地重新启动所有进程：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:restart</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>此命令将指示所有队列进程在处理完当前任务后正常退出，以免丢失现有任务。由于队列任务将在执行<code v-pre>queue:restart</code> 命令时退出，你应该运行诸如 <a href="#supervisor-configuration">Supervisor</a>之类的进程管理器来自动重新启动队列任务。</p>
<blockquote>
<p><strong>注意</strong><br>
队列使用 <a href="https://learnku.com/docs/laravel/11.x/cachemd" target="_blank" rel="noopener noreferrer">cache</a> 来存储重启信号，因此你应该在使用此功能之前验证是否为你的应用程序正确配置了缓存驱动程序</p>
</blockquote>
<h3 id="任务到期-超时" tabindex="-1"><a class="header-anchor" href="#任务到期-超时"><span>任务到期 &amp; 超时</span></a></h3>
<h4 id="任务到期" tabindex="-1"><a class="header-anchor" href="#任务到期"><span>任务到期</span></a></h4>
<p>在 <code v-pre>config/queue.php</code> 配置文件中，每个队列连接都定义了一个 <code v-pre>retry_after</code> 选项。该选项指定队列连接在重试正在处理的作业之前应该等待多少秒。例如，如果 <code v-pre>retry_after</code> 的值设置为 <code v-pre>90</code>，如果作业已经处理了 90 秒而没有被释放或删除，则该作业将被释放回队列。通常，你应该将 <code v-pre>retry_after</code> 值设置为作业完成处理所需的最大秒数。</p>
<blockquote>
<p><strong>警告</strong><br>
唯一不包含 <code v-pre>retry_after</code> 值的队列连接是 Amazon SQS。SQS 将根据 AWS 控制台内管理的 <a href="https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/AboutVT.html" target="_blank" rel="noopener noreferrer">默认可见性超时</a> 重试作业。</p>
</blockquote>
<h4 id="进程超时" tabindex="-1"><a class="header-anchor" href="#进程超时"><span>进程超时</span></a></h4>
<p><code v-pre>queue:work</code> Artisan 命令暴露了一个 <code v-pre>--timeout</code> 选项。默认情况下，<code v-pre>--timeout</code> 值为 60 秒。如果一个任务的处理时间超过了超时值指定的秒数，处理该任务的进程将会出错退出。通常，进程会被配置在你服务器上的 <a href="#supervisor-configuration">进程管理器</a> 自动重启：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:work <span class="token parameter variable">--timeout</span><span class="token operator">=</span><span class="token number">60</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p><code v-pre>retry_after</code> 配置选项和 <code v-pre>--timeout</code> CLI 选项是不同的，但它们协同工作以确保任务不会丢失并且任务仅成功处理一次。</p>
<blockquote>
<p><strong>警告</strong><br>
<code v-pre>--timeout</code> 值应始终至少比 <code v-pre>retry_after</code> 配置值短几秒钟。这将确保处理冻结任务的进程在任务被重试之前总是被终止。如果你的 <code v-pre>--timeout</code> 选项比 <code v-pre>retry_after</code> 配置值长，你的任务可能会被处理两次。</p>
</blockquote>
<h2 id="supervisor-配置" tabindex="-1"><a class="header-anchor" href="#supervisor-配置"><span>Supervisor 配置</span></a></h2>
<p>在生产中，你需要一种方法来保持 <code v-pre>queue:work</code> 进程运行。 <code v-pre>queue:work</code> 进程可能会因多种原因停止运行，例如超过 worker 超时或执行 <code v-pre>queue:restart</code> 命令。<br>
在生产环境中，你需要一种方法来保持你的 <code v-pre>queue:work</code> 进程运行。<code v-pre>queue:work</code> 进程可能会因各种原因停止运行，例如超过进程超时或执行 <code v-pre>queue:restart</code> 命令。</p>
<p>因此，你需要配置一个进程监视器，可以检测你的 <code v-pre>queue:work</code> 进程何时退出并自动重启它们。此外，进程监视器可以让你指定希望同时运行多少个 <code v-pre>queue:work</code> 进程。Supervisor 是 Linux 环境中常用的进程监视器，我们将在以下文档中讨论如何配置它。</p>
<h4 id="worker-超时" tabindex="-1"><a class="header-anchor" href="#worker-超时"><span>Worker 超时</span></a></h4>
<p>The <code v-pre>queue:work</code> Artisan 命令提供了一个 <code v-pre>--timeout</code> 选项。默认情况下， <code v-pre>--timeout</code> v值为 60 秒。如果一个任务处理时间超过了超时值指定的秒数，处理该任务的 worker 将以错误退出。 通常，worker 会被 <a href="#supervisor-configuration">在你服务器上配置的进程管理器</a>自动重启：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:work <span class="token parameter variable">--timeout</span><span class="token operator">=</span><span class="token number">60</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p><code v-pre>retry_after</code> 配置选项和 <code v-pre>--timeout</code> CLI 选项是不同的，但它们协同工作以确保任务不会丢失，并且任务只被成功处理一次。</p>
<blockquote>
<p><strong>警告</strong><br>
<code v-pre>--timeout</code> 值应该始终比你的 <code v-pre>retry_after</code> 配置值至少短几秒。这将确保处理冻结任务的 worker 在任务重试之前总是被终止。如果你的 <code v-pre>--timeout</code> 选项长于你的 <code v-pre>retry_after</code> 配置值，你的任务可能会被处理两次。</p>
</blockquote>
<h2 id="supervisor-配置-1" tabindex="-1"><a class="header-anchor" href="#supervisor-配置-1"><span>Supervisor 配置</span></a></h2>
<p>在生产环境中，你需要一种方法来保持你的 <code v-pre>queue:work</code> 进程持续运行。 <code v-pre>queue:work</code> 进程可能由于各种原因停止运行，比如超过了 worker 超时时间或执行了 <code v-pre>queue:restart</code> 命令。</p>
<p>因此，你需要配置一个进程监视器，它能够检测到 <code v-pre>queue:work</code> 进程何时退出并自动重启它们。此外，进程监视器还可以让你指定想要同时运行多少个 <code v-pre>queue:work</code> 进程。Supervisor 是一个在 Linux 环境中常用的进程监视器，我们将在接下来的文档中讨论如何配置它。</p>
<h4 id="安装-supervisor" tabindex="-1"><a class="header-anchor" href="#安装-supervisor"><span>安装 Supervisor</span></a></h4>
<p>Supervisor 是一个用于 Linux 操作系统的进程监视器，它会在你的 <code v-pre>queue:work</code> 进程失败时自动重启它们。要在 Ubuntu 上安装 Supervisor，你可以使用以下命令：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line"><span class="token function">sudo</span> <span class="token function">apt-get</span> <span class="token function">install</span> supervisor</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p><strong>提示</strong><br>
如果自己配置和管理 Supervisor 感觉有点力不从心，可以考虑使用 <a href="https://forge.laravel.com/" target="_blank" rel="noopener noreferrer">Laravel Forge</a>，它会为你的生产环境 Laravel 项目自动安装和配置 Supervisor。</p>
</blockquote>
<h4 id="配置-supervisor" tabindex="-1"><a class="header-anchor" href="#配置-supervisor"><span>配置 Supervisor</span></a></h4>
<p>Supervisor 配置文件通常存储在 <code v-pre>/etc/supervisor/conf.d</code> 目录中。在这个目录中，你可以创建任意数量的配置文件，指示 supervisor 如何监控你的进程。例如，让我们创建一个 <code v-pre>laravel-worker.conf</code> 文件，用于启动和监控 <code v-pre>queue:work</code> 进程：</p>
<div class="language-ini line-numbers-mode" data-highlighter="prismjs" data-ext="ini" data-title="ini"><pre v-pre class="language-ini"><code><span class="line"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">program:laravel-worker</span><span class="token punctuation">]</span></span></span>
<span class="line"><span class="token key attr-name">process_name</span><span class="token punctuation">=</span><span class="token value attr-value">%(program_name)s_%(process_num)02d</span></span>
<span class="line"><span class="token key attr-name">command</span><span class="token punctuation">=</span><span class="token value attr-value">php /home/forge/app.com/artisan queue:work sqs --sleep=3 --tries=3 --max-time=3600</span></span>
<span class="line"><span class="token key attr-name">autostart</span><span class="token punctuation">=</span><span class="token value attr-value">true</span></span>
<span class="line"><span class="token key attr-name">autorestart</span><span class="token punctuation">=</span><span class="token value attr-value">true</span></span>
<span class="line"><span class="token key attr-name">stopasgroup</span><span class="token punctuation">=</span><span class="token value attr-value">true</span></span>
<span class="line"><span class="token key attr-name">killasgroup</span><span class="token punctuation">=</span><span class="token value attr-value">true</span></span>
<span class="line"><span class="token key attr-name">user</span><span class="token punctuation">=</span><span class="token value attr-value">forge</span></span>
<span class="line"><span class="token key attr-name">numprocs</span><span class="token punctuation">=</span><span class="token value attr-value">8</span></span>
<span class="line"><span class="token key attr-name">redirect_stderr</span><span class="token punctuation">=</span><span class="token value attr-value">true</span></span>
<span class="line"><span class="token key attr-name">stdout_logfile</span><span class="token punctuation">=</span><span class="token value attr-value">/home/forge/app.com/worker.log</span></span>
<span class="line"><span class="token key attr-name">stopwaitsecs</span><span class="token punctuation">=</span><span class="token value attr-value">3600</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在这个例子中， <code v-pre>numprocs</code> 指令将指示 Supervisor 运行 8 个 <code v-pre>queue:work</code> 进程并监控所有这些进程，如果它们失败则自动重启。你应该修改配置的 <code v-pre>command</code> 指令以反映你想要的队列连接和 worker 选项。</p>
<blockquote>
<p><strong>警告</strong><br>
你应该确保 <code v-pre>stopwaitsecs</code> 的值大于你最长运行的任务所消耗的秒数。否则，Supervisor 可能会在任务处理完成之前终止它。</p>
</blockquote>
<h4 id="启动-supervisor" tabindex="-1"><a class="header-anchor" href="#启动-supervisor"><span>启动 Supervisor</span></a></h4>
<p>创建配置文件后，你可以使用以下命令更新 Supervisor 配置并启动进程：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line"><span class="token function">sudo</span> supervisorctl reread</span>
<span class="line"></span>
<span class="line"><span class="token function">sudo</span> supervisorctl update</span>
<span class="line"></span>
<span class="line"><span class="token function">sudo</span> supervisorctl start <span class="token string">"laravel-worker:*"</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>有关 Supervisor 的更多信息，请查阅 <a href="http://supervisord.org/index.html" target="_blank" rel="noopener noreferrer">Supervisor 文档</a>。</p>
<h2 id="处理失败的任务" tabindex="-1"><a class="header-anchor" href="#处理失败的任务"><span>处理失败的任务</span></a></h2>
<p>有时候你的队列任务可能会失败。别担心，事情不总是按计划进行！Laravel 提供了一种方便的方式来<a href="#max-job-attempts-and-timeout">指定任务尝试的最大次数</a>。在一个异步任务尝试次数超过这个数量后，它将被插入到 <code v-pre>failed_jobs</code> 数据库表中。<a href="https://learnku.com/docs/laravel/11.x/queuesmd#synchronous-dispatching" target="_blank" rel="noopener noreferrer">同步调度任务</a> 如果失败了，则不会存储在这个表中，它们的异常会立即被应用程序处理。</p>
<p>在新的 Laravel 应用程序中通常会预设一个用于创建 <code v-pre>failed_jobs</code> 表的迁移。然而，如果你的应用程序没有包含这个表的迁移，你可以使用 <code v-pre>make:queue-failed-table</code> 命令来创建迁移：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan make:queue-failed-table</span>
<span class="line"></span>
<span class="line">php artisan migrate</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当运行一个 <a href="#running-the-queue-worker">queue worker</a> 进程时，你可以使用 <code v-pre>queue:work</code> 命令的 <code v-pre>--tries</code> 开关来指定任务尝试的最大次数。如果你没有为 <code v-pre>--tries</code> 选项指定一个值，则任务将仅尝试一次或与任务类的 <code v-pre>$tries</code> 属性指定的次数相同：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:work redis <span class="token parameter variable">--tries</span><span class="token operator">=</span><span class="token number">3</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>使用 <code v-pre>--backoff</code> 选项，你可以指定 Laravel 在重试遇到异常的任务之前应该等待多少秒。默认情况下，任务会立即释放回队列，以便可以再次尝试：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:work redis <span class="token parameter variable">--tries</span><span class="token operator">=</span><span class="token number">3</span> <span class="token parameter variable">--backoff</span><span class="token operator">=</span><span class="token number">3</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>如果你想配置 Laravel 在重试每个任务遇到异常的任务之前应该等待多少秒，你可以通过在你的任务类上定义一个 <code v-pre>backoff</code> 属性来实现：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 重试任务前等待的秒数</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@var</span> <span class="token class-name"><span class="token keyword">int</span></span></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token variable">$backoff</span> <span class="token operator">=</span> <span class="token number">3</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你需要更复杂的逻辑来确定任务的退避时间，你可以在你的任务类上定义一个 <code v-pre>backoff</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line">* 计算重试任务之前要等待的秒数</span>
<span class="line">*/</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">backoff</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">int</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token number">3</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你可以通过从 <code v-pre>backoff</code> 方法返回一组退避值来轻松配置 「exponential」 退避。在此示例中，第一次重试的重试延迟为 1 秒，第二次重试为 5 秒，第三次重试为 10 秒，如果后续有更多重试，则重试延迟为10秒:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line">* 计算重试任务之前要等待的秒数</span>
<span class="line">*</span>
<span class="line">* <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">array</span></span>&lt;int, int></span>
<span class="line">*/</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">backoff</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">array</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="任务失败后清理" tabindex="-1"><a class="header-anchor" href="#任务失败后清理"><span>任务失败后清理</span></a></h3>
<p>当特定任务失败时，你可能希望向用户发送警报或恢复该任务部分完成的任何操作。为此，你可以在任务类上定义一个 <code v-pre>failed</code> 方法。导致作业失败的 <code v-pre>Throwable</code> 实例将被传递给 <code v-pre>failed</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Jobs</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Podcast</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Services<span class="token punctuation">\</span>AudioProcessor</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Bus<span class="token punctuation">\</span>Queueable</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>ShouldQueue</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>InteractsWithQueue</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>SerializesModels</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Throwable</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">ProcessPodcast</span> <span class="token keyword">implements</span> <span class="token class-name">ShouldQueue</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">use</span> <span class="token package">InteractsWithQueue</span><span class="token punctuation">,</span> Queueable<span class="token punctuation">,</span> SerializesModels<span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 创建新任务实例</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">__construct</span><span class="token punctuation">(</span></span>
<span class="line">        <span class="token keyword">public</span> <span class="token class-name type-declaration">Podcast</span> <span class="token variable">$podcast</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 执行任务</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">handle</span><span class="token punctuation">(</span><span class="token class-name type-declaration">AudioProcessor</span> <span class="token variable">$processor</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token comment">// 理上传的播客...</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 处理失败作业</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">failed</span><span class="token punctuation">(</span><span class="token operator">?</span><span class="token class-name type-declaration">Throwable</span> <span class="token variable">$exception</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token comment">// 向用户发送失败通知等...</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>注意</strong><br>
调用 <code v-pre>failed</code> 方法之前前会实例化任务的新实例；因此，在 <code v-pre>handle</code> 方法中可能发生的任何类属性修改都将丢失。</p>
</blockquote>
<h3 id="重试失败的任务" tabindex="-1"><a class="header-anchor" href="#重试失败的任务"><span>重试失败的任务</span></a></h3>
<p>要查看已插入到你的 <code v-pre>failed_jobs</code> 数据库表中的所有失败任务，你可以使用 <code v-pre>queue:failed</code> Artisan 命令：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:failed</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p><code v-pre>queue:failed</code> 命令会列出任务 ID、连接、队列、失败时间以及关于任务的其他信息。可以使用任务 ID 来重试失败的任务。例如，要重试一个 ID 为 <code v-pre>ce7bb17c-cdd8-41f0-a8ec-7b4fef4e5ece</code> 的失败任务，请执行以下命令：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:retry ce7bb17c-cdd8-41f0-a8ec-7b4fef4e5ece</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>如有必要，可以向命令传递多个 ID:</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:retry ce7bb17c-cdd8-41f0-a8ec-7b4fef4e5ece 91401d2c-0784-4f43-824c-34f94a33c24d</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>还可以重试指定队列的所有失败任务：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:retry <span class="token parameter variable">--queue</span><span class="token operator">=</span>name</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>重试所有失败任务，可以执行 <code v-pre>queue:retry</code> 命令，并将 <code v-pre>all</code> 作为 ID 传递：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:retry all</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>如果要删除指定的失败任务，可以使用 <code v-pre>queue:forget</code> 命令：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:forget 91401d2c-0784-4f43-824c-34f94a33c24d</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p><strong>技巧</strong><br>
使用 <a href="https://learnku.com/docs/laravel/11.x/horizonmd" target="_blank" rel="noopener noreferrer">Horizon</a> 时，应该使用 <code v-pre>Horizon:forget</code> 命令来删除失败任务，而不是 <code v-pre>queue:forget</code> 命令。</p>
</blockquote>
<p>删除 <code v-pre>failed_jobs</code> 表中所有失败任务，可以使用 <code v-pre>queue:flush</code> 命令:</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:flush</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="忽略缺失的模型" tabindex="-1"><a class="header-anchor" href="#忽略缺失的模型"><span>忽略缺失的模型</span></a></h3>
<p>在将 Eloquent 模型注入到任务中时，这个模型会在放置到队列之前自动序列化，并在任务处理时重新从数据库获取。然而，如果模型在任务等待消费时被删除了，则任务可能会失败，抛出 <code v-pre>ModelNotFoundException</code> 异常。</p>
<p>为了方便起见，你可以通过将任务的 <code v-pre>deleteWhenMissingModels</code> 属性设置为 <code v-pre>true</code> 来选择自动删除缺失模型的任务。当这个属性设置为 <code v-pre>true</code> 时，Laravel 会安静地丢弃任务，而不会引发异常：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 如果任务的模型不存在，则删除该任务</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@var</span> <span class="token class-name"><span class="token keyword">bool</span></span></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token variable">$deleteWhenMissingModels</span> <span class="token operator">=</span> <span class="token constant boolean">true</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="删除失败的任务" tabindex="-1"><a class="header-anchor" href="#删除失败的任务"><span>删除失败的任务</span></a></h3>
<p>你可以通过调用 <code v-pre>queue:prune-failed</code> Artisan 命令删除应用程序的 <code v-pre>failed_jobs</code> 表中的所有记录：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:prune-failed</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>默认情况下，将删除所有超过 24 小时的失败任务记录，如果为命令提供 <code v-pre>--hours</code> 选项，则仅保留在过去 N 小时内插入的失败任务记录。例如，以下命令将删除超过 48 小时前插入的所有失败任务记录：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:prune-failed <span class="token parameter variable">--hours</span><span class="token operator">=</span><span class="token number">48</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="在-dynamodb-中存储失败的任务" tabindex="-1"><a class="header-anchor" href="#在-dynamodb-中存储失败的任务"><span>在 DynamoDB 中存储失败的任务</span></a></h3>
<p>Laravel 也支持在 <a href="https://aws.amazon.com/dynamodb" target="_blank" rel="noopener noreferrer">DynamoDB</a> 中而非关系型数据库表中存储失败作业的记录。然而，你必须手动创建一个 DynamoDB 表来存储所有的失败作业记录。通常，这个表应该被命名为 <code v-pre>failed_jobs</code>，但你应该根据应用程序的 <code v-pre>queue</code> 配置文件中 <code v-pre>queue.failed.table</code> 配置值来命名表。</p>
<p><code v-pre>failed_jobs</code> 表应该有一个名为 <code v-pre>application</code> 的字符串主分区键，以及一个名为 <code v-pre>uuid</code> 的字符串主排序键。键的 <code v-pre>application</code> 部分将包含你的应用程序名称，该名称由应用程序的 <code v-pre>app</code> 配置文件中的 <code v-pre>name</code> 配置值定义。由于应用程序名称是 DynamoDB 表键的一部分，你可以使用同一个表来存储多个 Laravel 应用程序的失败任务。</p>
<p>此外，请确保你安装了 AWS SDK 以便你的 Laravel 应用程序可以与 Amazon DynamoDB 通信：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line"><span class="token function">composer</span> require aws/aws-sdk-php</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>接下来，将 <code v-pre>queue.failed.driver</code> 配置选项的值设置为 <code v-pre>dynamodb</code>。此外，你应该在失败任务配置数组中定义 <code v-pre>key</code>、<code v-pre>secret</code> 和 <code v-pre>region</code> 配置选项。这些选项将被用于与 AWS 进行认证。使用 <code v-pre>dynamodb</code> 驱动时，<code v-pre>queue.failed.database</code> 配置选项不是必须的：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token string single-quoted-string">'failed'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'driver'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'QUEUE_FAILED_DRIVER'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'dynamodb'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'key'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'AWS_ACCESS_KEY_ID'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'secret'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'AWS_SECRET_ACCESS_KEY'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'region'</span> <span class="token operator">=></span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'AWS_DEFAULT_REGION'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'us-east-1'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'table'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'failed_jobs'</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="禁用失败任务的存储" tabindex="-1"><a class="header-anchor" href="#禁用失败任务的存储"><span>禁用失败任务的存储</span></a></h3>
<p>你可以通过将 <code v-pre>queue.failed.driver</code> 配置选项的值设置为 <code v-pre>null</code> 来指示 Laravel 不存储失败的任务。通常，这通过 <code v-pre>QUEUE_FAILED_DRIVER</code> 环境变量来完成：</p>
<div class="language-ini line-numbers-mode" data-highlighter="prismjs" data-ext="ini" data-title="ini"><pre v-pre class="language-ini"><code><span class="line"><span class="token key attr-name">QUEUE_FAILED_DRIVER</span><span class="token punctuation">=</span><span class="token value attr-value">null</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="失败任务事件" tabindex="-1"><a class="header-anchor" href="#失败任务事件"><span>失败任务事件</span></a></h3>
<p>如果你想注册一个在任务失败时调用的事件监听器，你可以使用 <code v-pre>Queue</code> facade 的 <code v-pre>failing</code> 方法。例如，我们可以在 Laravel 中包含的 <code v-pre>AppServiceProvider</code> 的 <code v-pre>boot</code> 方法中附加一个闭包到这个事件：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Providers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Queue</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>ServiceProvider</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>Events<span class="token punctuation">\</span>JobFailed</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">AppServiceProvider</span> <span class="token keyword">extends</span> <span class="token class-name">ServiceProvider</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     *  注册任何应用程序服务</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">register</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token comment">// ...</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 引导任何应用程序服务</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token class-name static-context">Queue</span><span class="token operator">::</span><span class="token function">failing</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">JobFailed</span> <span class="token variable">$event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token comment">// $event->connectionName</span></span>
<span class="line">            <span class="token comment">// $event->job</span></span>
<span class="line">            <span class="token comment">// $event->exception</span></span>
<span class="line">        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="从队列中清除任务" tabindex="-1"><a class="header-anchor" href="#从队列中清除任务"><span>从队列中清除任务</span></a></h2>
<blockquote>
<p><strong>技巧</strong><br>
使用 <a href="https://learnku.com/docs/laravel/11.x/horizonmd" target="_blank" rel="noopener noreferrer">Horizon</a> 时，应使用 <code v-pre>horizon:clear</code> 命令从队列中清除作业，而不是使用 <code v-pre>queue:clear</code> 命令。</p>
</blockquote>
<p>如果你想从默认连接的默认队列中删除所有任务，你可以使用 <code v-pre>queue:clear</code> Artisan 命令来执行此操作：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:clear</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>你还可以提供 <code v-pre>connection</code> 参数和 <code v-pre>queue</code> 选项以从特定连接和队列中删除任务：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:clear redis <span class="token parameter variable">--queue</span><span class="token operator">=</span>emails</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p><strong>注意</strong><br>
从队列中清除任务仅适用于 SQS、Redis 和数据库队列驱动程序。 此外，SQS 消息删除过程最多需要 60 秒，因此在你清除队列后 60 秒内发送到 SQS 队列的任务也可能会被删除。</p>
</blockquote>
<h2 id="监控你的队列" tabindex="-1"><a class="header-anchor" href="#监控你的队列"><span>监控你的队列</span></a></h2>
<p>如果你的队列突然涌入了大量的任务，它会导致队列任务繁重，从而增加了任务的完成时间，想你所想， Laravel 可以在队列执行超过设定的阈值时候提醒你。</p>
<p>首先， 你应该<a href="https://learnku.com/docs/laravel/11.x/schedulingmd" target="_blank" rel="noopener noreferrer">每分钟运行一次</a> <code v-pre>queue:monitor</code> 命令。这个命令可以设定任务的名称，以及你想要设定的任务数量阈值：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan queue:monitor redis:default,redis:deployments <span class="token parameter variable">--max</span><span class="token operator">=</span><span class="token number">100</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>仅仅调度此命令并不足以触发通知提醒你队列状态不堪重负。当命令遇到任务数量超过你的阈值的队列时，将会触发 <code v-pre>Illuminate\Queue\Events\QueueBusy</code> 事件。你可以在应用程序的 <code v-pre>AppServiceProvider</code> 中监听这个事件来向你或你的开发团队发送通知：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Notifications<span class="token punctuation">\</span>QueueHasLongWaitTime</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>Events<span class="token punctuation">\</span>QueueBusy</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Event</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Notification</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 启动任何应用程序服务</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Event</span><span class="token operator">::</span><span class="token function">listen</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">QueueBusy</span> <span class="token variable">$event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token class-name static-context">Notification</span><span class="token operator">::</span><span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'mail'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'dev@example.com'</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token operator">-></span><span class="token function">notify</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">QueueHasLongWaitTime</span><span class="token punctuation">(</span></span>
<span class="line">                    <span class="token variable">$event</span><span class="token operator">-></span><span class="token property">connection</span><span class="token punctuation">,</span></span>
<span class="line">                    <span class="token variable">$event</span><span class="token operator">-></span><span class="token property">queue</span><span class="token punctuation">,</span></span>
<span class="line">                    <span class="token variable">$event</span><span class="token operator">-></span><span class="token property">size</span></span>
<span class="line">                <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="测试" tabindex="-1"><a class="header-anchor" href="#测试"><span>测试</span></a></h2>
<p>在测试调度任务的代码时，你可能希望指示 Laravel 实际上不执行任务本身，因为任务的代码可以直接单独地测试，而不是与调度它的代码一起测试。当然，为了测试任务本身，你可以在测试中实例化一个任务实例并直接调用 <code v-pre>handle</code> 方法。</p>
<p>你可以使用 <code v-pre>Queue</code> facade 的 <code v-pre>fake</code> 方法来阻止排队的任务被实际推送到队列。在调用了 <code v-pre>Queue</code> facade 的 <code v-pre>fake</code> 方法之后，你可以断言应用程序试图推送任务到队列：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"><span class="token comment">//译者注：Pest 示例</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>AnotherJob</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>FinalJob</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>ShipOrder</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Queue</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'orders can be shipped'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Queue</span><span class="token operator">::</span><span class="token function">fake</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// 执行订单发货...</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// 断言没有任务被推送......</span></span>
<span class="line">    <span class="token class-name static-context">Queue</span><span class="token operator">::</span><span class="token function">assertNothingPushed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// 断言一个任务被推送到一个给定的队列...</span></span>
<span class="line">    <span class="token class-name static-context">Queue</span><span class="token operator">::</span><span class="token function">assertPushedOn</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'queue-name'</span><span class="token punctuation">,</span> <span class="token class-name static-context">ShipOrder</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// 断言任务被推了两次...</span></span>
<span class="line">    <span class="token class-name static-context">Queue</span><span class="token operator">::</span><span class="token function">assertPushed</span><span class="token punctuation">(</span><span class="token class-name static-context">ShipOrder</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// 断言任务没有被推送...</span></span>
<span class="line">    <span class="token class-name static-context">Queue</span><span class="token operator">::</span><span class="token function">assertNotPushed</span><span class="token punctuation">(</span><span class="token class-name static-context">AnotherJob</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// 断言闭包被推送到队列中...</span></span>
<span class="line">    <span class="token class-name static-context">Queue</span><span class="token operator">::</span><span class="token function">assertClosurePushed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// 断言推送的作业总数…</span></span>
<span class="line">    <span class="token class-name static-context">Queue</span><span class="token operator">::</span><span class="token function">assertCount</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"><span class="token comment">//译者注：PHPUnit 示例</span></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">Tests<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>AnotherJob</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>FinalJob</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>ShipOrder</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Queue</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Tests<span class="token punctuation">\</span>TestCase</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">ExampleTest</span> <span class="token keyword">extends</span> <span class="token class-name">TestCase</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">test_orders_can_be_shipped</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token class-name static-context">Queue</span><span class="token operator">::</span><span class="token function">fake</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 执行订单发货...</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 断言没有任务被推送......</span></span>
<span class="line">        <span class="token class-name static-context">Queue</span><span class="token operator">::</span><span class="token function">assertNothingPushed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 断言一个任务被推送到一个给定的队列...</span></span>
<span class="line">        <span class="token class-name static-context">Queue</span><span class="token operator">::</span><span class="token function">assertPushedOn</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'queue-name'</span><span class="token punctuation">,</span> <span class="token class-name static-context">ShipOrder</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 断言任务被推了两次...</span></span>
<span class="line">        <span class="token class-name static-context">Queue</span><span class="token operator">::</span><span class="token function">assertPushed</span><span class="token punctuation">(</span><span class="token class-name static-context">ShipOrder</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 断言任务没有被推送...</span></span>
<span class="line">        <span class="token class-name static-context">Queue</span><span class="token operator">::</span><span class="token function">assertNotPushed</span><span class="token punctuation">(</span><span class="token class-name static-context">AnotherJob</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 断言闭包被推送到队列中...</span></span>
<span class="line">        <span class="token class-name static-context">Queue</span><span class="token operator">::</span><span class="token function">assertClosurePushed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 断言推送的作业总数…</span></span>
<span class="line">        <span class="token class-name static-context">Queue</span><span class="token operator">::</span><span class="token function">assertCount</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你可以将一个闭包传递给 <code v-pre>assertPushed</code> 或 <code v-pre>assertNotPushed</code> 方法来断言推送了一个通过特定「真实性测试」的任务。如果至少有一个推送的任务通过了给定的真实测试，则断言将成功：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Queue</span><span class="token operator">::</span><span class="token function">assertPushed</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">ShipOrder</span> <span class="token variable">$job</span><span class="token punctuation">)</span> <span class="token keyword">use</span> <span class="token punctuation">(</span><span class="token variable">$order</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$job</span><span class="token operator">-></span><span class="token property">order</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$order</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="伪造任务的一个子集" tabindex="-1"><a class="header-anchor" href="#伪造任务的一个子集"><span>伪造任务的一个子集</span></a></h3>
<p>如果你只需要伪造特定的任务，同时允许你的其他任务正常执行，你可以将应该伪造的任务的类名传递给 <code v-pre>fake</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token comment">//译者注：Pest 示例</span></span>
<span class="line"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'orders can be shipped'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Queue</span><span class="token operator">::</span><span class="token function">fake</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">        <span class="token class-name static-context">ShipOrder</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// 执行订单发货...</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// 断言任务被推了两次......</span></span>
<span class="line">    <span class="token class-name static-context">Queue</span><span class="token operator">::</span><span class="token function">assertPushed</span><span class="token punctuation">(</span><span class="token class-name static-context">ShipOrder</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token comment">//译者注：PHPUnit 示例</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">test_orders_can_be_shipped</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Queue</span><span class="token operator">::</span><span class="token function">fake</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">        <span class="token class-name static-context">ShipOrder</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// 执行订单发货...</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// 断言任务被推了两次......</span></span>
<span class="line">    <span class="token class-name static-context">Queue</span><span class="token operator">::</span><span class="token function">assertPushed</span><span class="token punctuation">(</span><span class="token class-name static-context">ShipOrder</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你可以使用 <code v-pre>except</code> 方法伪造除一组指定任务之外的所有任务：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Queue</span><span class="token operator">::</span><span class="token function">fake</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">except</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token class-name static-context">ShipOrder</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="测试任务链" tabindex="-1"><a class="header-anchor" href="#测试任务链"><span>测试任务链</span></a></h3>
<p>要测试任务链，你需要使用 <code v-pre>Bus</code> facade 的伪造功能。可以使用 <code v-pre>Bus</code> facade 的 <code v-pre>assertChained</code> 方法来断言<a href="https://learnku.com/docs/laravel/11.x/queuesmd#job-chaining" target="_blank" rel="noopener noreferrer">任务链</a> 已经被分派。<code v-pre>assertChained</code> 方法接受一个链式任务数组作为其第一个参数：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>RecordShipment</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>ShipOrder</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>UpdateInventory</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Bus</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Bus</span><span class="token operator">::</span><span class="token function">fake</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// ...</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Bus</span><span class="token operator">::</span><span class="token function">assertChained</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token class-name static-context">ShipOrder</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token class-name static-context">RecordShipment</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token class-name static-context">UpdateInventory</span><span class="token operator">::</span><span class="token keyword">class</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>正如你在上面的示例中看到的，链式任务数组可能是任务类名称的数组。 但是，你也可以提供一组实际的任务实例。 这样做时，Laravel 将确保任务实例属于同一类，并且与你的应用程序调度的链式任务具有相同的属性值：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Bus</span><span class="token operator">::</span><span class="token function">assertChained</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">ShipOrder</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">RecordShipment</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">UpdateInventory</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你可以使用 <code v-pre>assertDispatchedWithoutChain</code> 方法来断言一个任务是在没有任务链的情况下被推送的：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Bus</span><span class="token operator">::</span><span class="token function">assertDispatchedWithoutChain</span><span class="token punctuation">(</span><span class="token class-name static-context">ShipOrder</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h4 id="测试任务链更改" tabindex="-1"><a class="header-anchor" href="#测试任务链更改"><span>测试任务链更改</span></a></h4>
<p>如果链式任务<a href="#adding-jobs-to-the-chain">将任务添加到现有链中</a>，你可以使用任务的 <code v-pre>assertHasChain</code> 方法来断言任务具有预期的剩余任务链：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$job</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ProcessPodcast</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$job</span><span class="token operator">-></span><span class="token function">handle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$job</span><span class="token operator">-></span><span class="token function">assertHasChain</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">TranscribePodcast</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">OptimizePodcast</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">ReleasePodcast</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>可以使用 <code v-pre>assertDoesntHaveChain</code> 方法来断言任务的剩余链为空：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$job</span><span class="token operator">-></span><span class="token function">assertDoesntHaveChain</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h4 id="测试链式批处理" tabindex="-1"><a class="header-anchor" href="#测试链式批处理"><span>测试链式批处理</span></a></h4>
<p>如果你的任务链<a href="#chains-and-batches">包含一个任务批处理</a>，你可以通过在链式断言中插入一个 <code v-pre>Bus::chainedBatch</code> 定义来断言链式批处理符合你的预期：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>ShipOrder</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>UpdateInventory</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Bus<span class="token punctuation">\</span>PendingBatch</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Bus</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Bus</span><span class="token operator">::</span><span class="token function">assertChained</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">ShipOrder</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token class-name static-context">Bus</span><span class="token operator">::</span><span class="token function">chainedBatch</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">PendingBatch</span> <span class="token variable">$batch</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token variable">$batch</span><span class="token operator">-></span><span class="token property">jobs</span><span class="token operator">-></span><span class="token function">count</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token number">3</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">new</span> <span class="token class-name">UpdateInventory</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="测试任务批处理" tabindex="-1"><a class="header-anchor" href="#测试任务批处理"><span>测试任务批处理</span></a></h3>
<p><code v-pre>Bus</code> facade 的 <code v-pre>assertBatched</code> 方法可以用来断言已经派发了一个<a href="https://learnku.com/docs/laravel/11.x/queuesmd#job-batching" target="_blank" rel="noopener noreferrer">任务批处理</a> 。提供给 <code v-pre>assertBatched</code> 方法的闭包接收到一个 <code v-pre>Illuminate\Bus\PendingBatch</code> 实例，该实例可用于检查批处理中的任务：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Bus<span class="token punctuation">\</span>PendingBatch</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Bus</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Bus</span><span class="token operator">::</span><span class="token function">fake</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// ...</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Bus</span><span class="token operator">::</span><span class="token function">assertBatched</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">PendingBatch</span> <span class="token variable">$batch</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$batch</span><span class="token operator">-></span><span class="token property">name</span> <span class="token operator">==</span> <span class="token string single-quoted-string">'import-csv'</span> <span class="token operator">&amp;&amp;</span></span>
<span class="line">           <span class="token variable">$batch</span><span class="token operator">-></span><span class="token property">jobs</span><span class="token operator">-></span><span class="token function">count</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token number">10</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你可以使用 <code v-pre>assertBatchCount</code> 方法来断言派发了特定数量的批处理：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Bus</span><span class="token operator">::</span><span class="token function">assertBatchCount</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>你可以使用 <code v-pre>assertNothingBatched</code> 来断言没有批处理被派发：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Bus</span><span class="token operator">::</span><span class="token function">assertNothingBatched</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h4 id="测试任务-批处理交互" tabindex="-1"><a class="header-anchor" href="#测试任务-批处理交互"><span>测试任务 / 批处理交互</span></a></h4>
<p>此外，你可能偶尔需要测试单个任务与其基础批处理的交互。例如，你可能需要测试任务否取消了其批处理的进一步处理。要做到这一点，你需要通过 <code v-pre>withFakeBatch</code> 方法为任务分配一个假批处理。<code v-pre>withFakeBatch</code> 方法返回一个包含任务实例和假批处理的元组：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token punctuation">[</span><span class="token variable">$job</span><span class="token punctuation">,</span> <span class="token variable">$batch</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">ShipOrder</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">withFakeBatch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$job</span><span class="token operator">-></span><span class="token function">handle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$this</span><span class="token operator">-></span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token variable">$batch</span><span class="token operator">-></span><span class="token function">cancelled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$this</span><span class="token operator">-></span><span class="token function">assertEmpty</span><span class="token punctuation">(</span><span class="token variable">$batch</span><span class="token operator">-></span><span class="token property">added</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="测试任务-队列交互" tabindex="-1"><a class="header-anchor" href="#测试任务-队列交互"><span>测试任务 / 队列交互</span></a></h3>
<p>有时候，你可能需要测试一个排队的任务是否<a href="#manually-releasing-a-job">将自己释放回队列</a>。或者，你可能需要测试任务是否已经删除了自己。你可以通过实例化任务并调用<code v-pre>withFakeQueueInteractions</code>方法来测试这些队列交互。</p>
<p>一旦任务的队列交互被模拟，你就可以调用作业的<code v-pre>handle</code>方法。调用任务之后，<code v-pre>assertReleased</code>、<code v-pre>assertDeleted</code>和<code v-pre>assertFailed</code>方法可用来对任务的队列交互进行断言：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Jobs<span class="token punctuation">\</span>ProcessPodcast</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$job</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">ProcessPodcast</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">withFakeQueueInteractions</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$job</span><span class="token operator">-></span><span class="token function">handle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$job</span><span class="token operator">-></span><span class="token function">assertReleased</span><span class="token punctuation">(</span><span class="token argument-name">delay</span><span class="token punctuation">:</span> <span class="token number">30</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$job</span><span class="token operator">-></span><span class="token function">assertDeleted</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$job</span><span class="token operator">-></span><span class="token function">assertFailed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="任务事件" tabindex="-1"><a class="header-anchor" href="#任务事件"><span>任务事件</span></a></h2>
<p>使用 Queue facade 上的 before 和 after 方法，你可以指定要在处理排队任务之前或之后执行的回调。 这些回调是为仪表板执行额外日志记录或增量统计的绝佳机会。 通常，你应该从 服务提供者 的 boot 方法中调用这些方法。 例如，我们可以使用 Laravel 自带的 AppServiceProvider：</p>
<p>使用 <code v-pre>Queue</code> <a href="https://learnku.com/docs/laravel/11.x/facadesmd" target="_blank" rel="noopener noreferrer">facade</a> 上的 <code v-pre>before</code> 和 <code v-pre>after</code> 方法，你可以指定在处理排队任务之前或之后执行的回调函数。这些回调函数是执行额外日志记录或为仪表板增加统计数据的绝佳机会。通常，你应该从<a href="https://learnku.com/docs/laravel/11.x/providersmd" target="_blank" rel="noopener noreferrer">服务提供者</a>的<code v-pre>boot</code>方法中调用这些方法。例如，我们可以使用 Laravel 自带的<code v-pre>AppServiceProvider</code>：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Providers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Queue</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>ServiceProvider</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>Events<span class="token punctuation">\</span>JobProcessed</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Queue<span class="token punctuation">\</span>Events<span class="token punctuation">\</span>JobProcessing</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">AppServiceProvider</span> <span class="token keyword">extends</span> <span class="token class-name">ServiceProvider</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 注册任何应用服务</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">register</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token comment">// ...</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 引导任何应用服务</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token class-name static-context">Queue</span><span class="token operator">::</span><span class="token function">before</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">JobProcessing</span> <span class="token variable">$event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token comment">// $event->connectionName</span></span>
<span class="line">            <span class="token comment">// $event->job</span></span>
<span class="line">            <span class="token comment">// $event->job->payload()</span></span>
<span class="line">        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token class-name static-context">Queue</span><span class="token operator">::</span><span class="token function">after</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">JobProcessed</span> <span class="token variable">$event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token comment">// $event->connectionName</span></span>
<span class="line">            <span class="token comment">// $event->job</span></span>
<span class="line">            <span class="token comment">// $event->job->payload()</span></span>
<span class="line">        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>使用 <code v-pre>Queue</code> <a href="https://learnku.com/docs/laravel/11.x/facadesmd/16656" target="_blank" rel="noopener noreferrer">facade</a> 上的<code v-pre>looping</code> 方法, 你可以在 worker 尝试从队列获取任务之前执行指定的回调。例如，你可以注册一个闭包，用以回滚之前失败任务打开的任何事务：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>DB</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Queue</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Queue</span><span class="token operator">::</span><span class="token function">looping</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token class-name static-context">DB</span><span class="token operator">::</span><span class="token function">transactionLevel</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token class-name static-context">DB</span><span class="token operator">::</span><span class="token function">rollBack</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p>本译文仅用于学习和交流目的，转载请务必注明文章译者、出处、和本文链接<br>
我们的翻译工作遵照 <a href="https://learnku.com/docs/guide/cc4.0/6589" target="_blank" rel="noopener noreferrer">CC 协议</a>，如果我们的工作有侵犯到您的权益，请及时联系我们。</p>
</blockquote>
<hr>
<blockquote>
<p>原文地址：<a href="https://learnku.com/docs/laravel/11.x/queuesmd/16686" target="_blank" rel="noopener noreferrer">https://learnku.com/docs/laravel/11.x/qu...</a></p>
<p>译文地址：<a href="https://learnku.com/docs/laravel/11.x/queuesmd/16686" target="_blank" rel="noopener noreferrer">https://learnku.com/docs/laravel/11.x/qu...</a></p>
</blockquote>
</div></template>


